├── MATLAB ├── Text_to_Image.m └── Image_to_Text.m ├── CPP ├── Timer.h ├── Makefile ├── Timer.cpp ├── Board.h ├── Board.cpp └── main.cpp ├── VHDL ├── regbit.vhd ├── register.vhd ├── rshift_2.vhd ├── rshift_3.vhd ├── rshift_1.vhd ├── controller.vhd ├── mult_pipe.vhd ├── comparator1.vhd ├── comparator.vhd ├── wrapper.vhd ├── sub_pipe.vhd ├── add_pipe.vhd ├── ip_address_generator_1.vhd ├── config_pkg.vhd ├── ip_address_generator_3.vhd ├── op_address_generator.vhd ├── ip_address_generator_2.vhd ├── threshold_comp.vhd ├── datapath_thresh.vhd ├── smartBuffer.vhd ├── smartBufferV.vhd ├── datapathGy.vhd ├── memory_map.vhd ├── op_ram.vhd ├── datapathGx.vhd ├── ip_ram.vhd ├── datapath.vhd ├── gxgyBuffer.vhd └── user_app.vhd └── README.md /MATLAB/Text_to_Image.m: -------------------------------------------------------------------------------- 1 | % script to convert text file to image 2 | fileID = fopen('out.txt', 'r'); 3 | A = fscanf(fileID, '%d'); 4 | B = vec2mat(A, 124); 5 | C = mat2gray(B); 6 | imshow(C); -------------------------------------------------------------------------------- /MATLAB/Image_to_Text.m: -------------------------------------------------------------------------------- 1 | % script to convert image to text file 2 | A = imread('Lenna.jpg'); 3 | B = imresize(A, [128 128]); 4 | C = rgb2gray(B); 5 | D = imgaussfilt(C); 6 | 7 | fileID = fopen('test.txt', 'w'); 8 | fprintf(fileID, '%d\n', D); 9 | fclose(fileID); 10 | -------------------------------------------------------------------------------- /CPP/Timer.h: -------------------------------------------------------------------------------- 1 | #ifndef _TIMER_H_ 2 | #define _TIMER_H_ 3 | 4 | class Timer 5 | { 6 | public: 7 | Timer(); 8 | ~Timer(); 9 | 10 | void start(); 11 | void stop(); 12 | double elapsedTime() const; 13 | 14 | protected: 15 | double startTime; 16 | double stopTime; 17 | 18 | double currentTime() const; 19 | }; 20 | 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /CPP/Makefile: -------------------------------------------------------------------------------- 1 | #CC = g++ 2 | CC = arm-linux-g++ 3 | CFLAGS = -O3 -Wall -ansi -g 4 | 5 | OBJS = main.o Board.o Timer.o 6 | 7 | #set up C suffixes & relationship between .cpp and .o files 8 | .SUFFIXES: .cpp 9 | 10 | .cpp.o: 11 | $(CC) $(CFLAGS) -c $< 12 | 13 | 14 | fabric: $(OBJS) 15 | ${CC} -o zed_app $(OBJS) 16 | 17 | main.o : Board.h Timer.h 18 | Board.o : Board.h 19 | Timer.o : Timer.h 20 | 21 | clean: 22 | rm -f *.o *~ zed_app 23 | 24 | # DO NOT DELETE 25 | -------------------------------------------------------------------------------- /CPP/Timer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "Timer.h" 5 | 6 | Timer::Timer() : startTime(0.0), stopTime(0.0) { 7 | 8 | } 9 | 10 | Timer::~Timer() { 11 | 12 | } 13 | 14 | double Timer::currentTime() const { 15 | 16 | timeval st; 17 | gettimeofday(&st,NULL); 18 | return st.tv_sec + st.tv_usec*1e-6; 19 | } 20 | 21 | void Timer::start() { 22 | 23 | startTime = currentTime(); 24 | } 25 | 26 | void Timer::stop() { 27 | 28 | stopTime = currentTime(); 29 | } 30 | 31 | double Timer::elapsedTime() const { 32 | 33 | return stopTime-startTime; 34 | } 35 | -------------------------------------------------------------------------------- /VHDL/regbit.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | 4 | entity regbit is 5 | port ( 6 | clk : in std_logic; 7 | rst : in std_logic; 8 | vld_in : in std_logic; 9 | input : in std_logic; 10 | output : out std_logic); 11 | end regbit; 12 | 13 | architecture BHV of regbit is 14 | begin 15 | process(clk, rst) 16 | begin 17 | if (rst = '1') then 18 | output <= '0'; 19 | elsif (clk'event and clk = '1') then 20 | if (vld_in = '1') then 21 | output <= input; 22 | end if; 23 | end if; 24 | end process; 25 | end BHV; 26 | -------------------------------------------------------------------------------- /VHDL/register.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | 4 | entity reg is 5 | generic ( 6 | width : positive := 16); 7 | port ( 8 | clk : in std_logic; 9 | rst : in std_logic; 10 | vld_in : in std_logic; 11 | input : in std_logic_vector(width-1 downto 0); 12 | output : out std_logic_vector(width-1 downto 0)); 13 | end reg; 14 | 15 | architecture BHV of reg is 16 | begin 17 | process(clk, rst) 18 | begin 19 | if (rst = '1') then 20 | output <= (others => '0'); 21 | elsif (clk'event and clk = '1') then 22 | if (vld_in = '1') then 23 | output <= input; 24 | end if; 25 | end if; 26 | end process; 27 | end BHV; 28 | -------------------------------------------------------------------------------- /VHDL/rshift_2.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.std_logic_1164.all ; 3 | ENTITY shift2 IS 4 | generic ( 5 | width : positive := 8); 6 | PORT ( 7 | clk : IN STD_LOGIC ; 8 | rst : IN STD_LOGIC ; 9 | en : IN STD_LOGIC ; 10 | R : IN STD_LOGIC_VECTOR(width-1 DOWNTO 0); 11 | Q : OUT STD_LOGIC_VECTOR(width-1 DOWNTO 0)); 12 | END shift2 ; 13 | 14 | ARCHITECTURE str OF shift2 IS 15 | 16 | BEGIN 17 | 18 | process (clk,rst) 19 | begin 20 | if(rst='1') then 21 | Q<=R; 22 | elsif(rising_edge(clk)) then 23 | if(en='1') then 24 | Q(0) <= R(2); 25 | Q(1) <= R(3); 26 | Q(2) <= R(4); 27 | Q(3) <= R(5); 28 | Q(4) <= R(6); 29 | Q(5) <= R(7); 30 | Q(6) <= '0'; 31 | Q(7) <= '0'; 32 | end if ; 33 | end if; 34 | end process ; 35 | 36 | end str ; -------------------------------------------------------------------------------- /VHDL/rshift_3.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.std_logic_1164.all ; 3 | ENTITY shift3 IS 4 | generic ( 5 | width : positive := 8); 6 | port ( 7 | clk : IN STD_LOGIC ; 8 | rst : IN STD_LOGIC ; 9 | en : IN STD_LOGIC ; 10 | R : IN STD_LOGIC_VECTOR(width-1 DOWNTO 0) ; 11 | Q : OUT STD_LOGIC_VECTOR(width-1 DOWNTO 0) ) ; 12 | END shift3 ; 13 | 14 | ARCHITECTURE str OF shift3 IS 15 | 16 | begin 17 | 18 | process (clk,rst) 19 | begin 20 | if(rst='1') then 21 | Q<=R; 22 | elsif(rising_edge(clk)) then 23 | if(en='1') then 24 | Q(0) <= R(3); 25 | Q(1) <= R(4); 26 | Q(2) <= R(5); 27 | Q(3) <= R(6); 28 | Q(4) <= R(7); 29 | Q(5) <= '0'; 30 | Q(6) <= '0'; 31 | Q(7) <= '0'; 32 | end if ; 33 | end if; 34 | end process ; 35 | 36 | end str ; -------------------------------------------------------------------------------- /VHDL/rshift_1.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee ; 2 | USE ieee.std_logic_1164.all ; 3 | ENTITY shift1 IS 4 | generic ( 5 | width : positive := 8); 6 | port ( 7 | clk : IN STD_LOGIC ; 8 | rst : IN STD_LOGIC ; 9 | en : IN STD_LOGIC ; 10 | R : IN STD_LOGIC_VECTOR(width-1 DOWNTO 0); 11 | Q : OUT STD_LOGIC_VECTOR(width-1 DOWNTO 0)); 12 | END shift1 ; 13 | 14 | ARCHITECTURE str OF shift1 IS 15 | 16 | BEGIN 17 | 18 | process (clk,rst) 19 | begin 20 | if(rst='1') then 21 | Q<=R; 22 | elsif(rising_edge(clk)) then 23 | if(en='1') then 24 | Q(0) <= R(1); 25 | Q(1) <= R(2); 26 | Q(2) <= R(3); 27 | Q(3) <= R(4); 28 | Q(4) <= R(5); 29 | Q(5) <= R(6); 30 | Q(6) <= R(7); 31 | Q(7) <= '0'; 32 | end if ; 33 | end if; 34 | end process ; 35 | 36 | end str ; -------------------------------------------------------------------------------- /VHDL/controller.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | entity controller is 6 | 7 | port ( 8 | clk : in std_logic; 9 | rst : in std_logic; 10 | go : in std_logic; 11 | done : out std_logic; 12 | data_vld : out std_logic; 13 | rslt_rdy : in std_logic 14 | ); 15 | 16 | end controller; 17 | 18 | architecture BHV of controller is 19 | 20 | begin 21 | 22 | process (clk, rst) 23 | begin 24 | if (rst = '1') then 25 | done <= '0'; 26 | data_vld <= '0'; 27 | 28 | elsif (rising_edge(clk)) then 29 | if (go = '1') then 30 | data_vld <= '1'; 31 | done <= '0'; 32 | elsif(go = '0') then 33 | if(rslt_rdy = '1') then 34 | data_vld <= '0'; 35 | done <= '1'; 36 | end if; 37 | end if; 38 | end if; 39 | end process; 40 | end BHV; 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FPGA Acceleration of Canny Edge Detection Algorithm 2 | 3 | Canny Edge Detection Algorithm is a multi-stage algorithm to detect wide range of edges in images. It can be broken down in to the following steps: 4 | * Apply Gaussian filter to smooth the image in order to remove the noise 5 | * Find the intensity gradients of the image 6 | * Apply non-maximum suppression to get rid of spurious response to edge detection 7 | * Apply double threshold to determine potential edges 8 | * Track edge by hysteresis: Finalize the detection of edges by suppressing all the other edges that are weak and not connected to strong edges. 9 | 10 | 11 | ### Directory Structure 12 | VHDL code for hardware implementation of algorithm is in the **VHDL** directory.
13 | CPP code for software implementation of algorithm is in the **CPP** directory.
14 | MATLAB scripts to convert image to text and vice versa is in the **MATLAB** directory. 15 | -------------------------------------------------------------------------------- /VHDL/mult_pipe.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | entity mult_pipe is 6 | generic ( 7 | width1 : positive := 16; 8 | width2 : positive := 16); 9 | port ( 10 | clk : in std_logic; 11 | rst : in std_logic; 12 | vld_in1 : in std_logic; 13 | in1 : in std_logic_vector(width1-1 downto 0); 14 | in2 : in std_logic_vector(width2-1 downto 0); 15 | output : out std_logic_vector(width1+width2-1 downto 0)); 16 | end mult_pipe; 17 | 18 | 19 | architecture BHV of mult_pipe is 20 | begin 21 | process(clk, rst) 22 | begin 23 | if rst = '1' then 24 | output <= (others => '0'); 25 | elsif rising_edge(clk) then 26 | if vld_in1 = '1' then 27 | output <= std_logic_vector(unsigned(in1) * unsigned(in2)); 28 | end if; 29 | end if; 30 | end process; 31 | end BHV; 32 | -------------------------------------------------------------------------------- /VHDL/comparator1.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | entity comparator1 is 6 | generic ( 7 | width : positive := 8); 8 | port ( 9 | clk : in std_logic; 10 | rst : in std_logic; 11 | en : in std_logic; 12 | in1 : in std_logic_vector(width+1 downto 0); 13 | in2 : in std_logic_vector(width-1 downto 0); 14 | result : out std_logic_vector(width+1 downto 0)); 15 | 16 | end comparator1; 17 | 18 | 19 | architecture bhv of comparator1 is 20 | 21 | begin 22 | process (clk,rst) 23 | begin 24 | if(rst='1') then 25 | result <= (others=> '0'); 26 | elsif(rising_edge(clk)) then 27 | if(en='1') then 28 | if (unsigned(in1) <= unsigned(in2)) then 29 | result <= std_logic_vector(resize(unsigned(in1), width+2)); 30 | else 31 | result <= in1; 32 | end if; 33 | end if; 34 | end if; 35 | 36 | end process; 37 | 38 | end bhv; 39 | -------------------------------------------------------------------------------- /VHDL/comparator.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | entity comparator is 6 | generic ( 7 | width : positive := 8); 8 | port ( 9 | clk : in std_logic; 10 | rst : in std_logic; 11 | en : in std_logic; 12 | in1 : in std_logic_vector(width-1 downto 0); 13 | in2 : in std_logic_vector(width-1 downto 0); 14 | max : out std_logic_vector(width-1 downto 0); 15 | min : out std_logic_vector(width-1 downto 0)); 16 | 17 | end comparator; 18 | 19 | 20 | architecture bhv of comparator is 21 | 22 | begin 23 | process (clk,rst) 24 | begin 25 | if(rst='1') then 26 | max <= (others=> '0'); 27 | min <= (others=> '0'); 28 | elsif(rising_edge(clk)) then 29 | if(en='1') then 30 | if (unsigned(in1) <= unsigned(in2)) then 31 | max<= in2; 32 | min<= in1; 33 | else 34 | max<= in1; 35 | min<= in2; 36 | end if; 37 | end if; 38 | end if; 39 | 40 | end process; 41 | 42 | end bhv; 43 | -------------------------------------------------------------------------------- /VHDL/wrapper.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | use work.config_pkg.all; 6 | 7 | entity wrapper is 8 | port( 9 | clk : in std_logic; 10 | rst : in std_logic; 11 | 12 | mmap_wr_en : in std_logic; 13 | mmap_wr_addr : in std_logic_vector(MMAP_ADDR_RANGE); 14 | mmap_wr_data : in std_logic_vector(MMAP_DATA_RANGE); 15 | mmap_rd_en : in std_logic; 16 | mmap_rd_addr : in std_logic_vector(MMAP_ADDR_RANGE); 17 | mmap_rd_data : out std_logic_vector(MMAP_DATA_RANGE) 18 | ); 19 | end wrapper; 20 | 21 | architecture default of wrapper is 22 | 23 | begin 24 | 25 | U_USER_APP : entity work.user_app 26 | port map ( 27 | clk => clk, 28 | rst => rst, 29 | 30 | mmap_wr_en => mmap_wr_en, 31 | mmap_wr_addr => mmap_wr_addr, 32 | mmap_wr_data => mmap_wr_data, 33 | 34 | mmap_rd_en => mmap_rd_en, 35 | mmap_rd_addr => mmap_rd_addr, 36 | mmap_rd_data => mmap_rd_data); 37 | 38 | end default; 39 | -------------------------------------------------------------------------------- /VHDL/sub_pipe.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | entity sub_pipe is 6 | generic ( 7 | width : positive := 16); 8 | port ( 9 | clk : in std_logic; 10 | rst : in std_logic; 11 | vld_in1 : in std_logic; 12 | in1 : in std_logic_vector(width-1 downto 0); 13 | in2 : in std_logic_vector(width-1 downto 0); 14 | output : out std_logic_vector(width downto 0)); 15 | end sub_pipe; 16 | 17 | -- TODO: Implement a behavioral description of a pipelined adder (i.e., an 18 | -- adder with a register on the output). The output should be one bit larger 19 | -- than the input, and should use the "width" generic as opposed to being 20 | -- hardcoded to a specific value. 21 | 22 | architecture BHV of sub_pipe is 23 | begin 24 | process(clk, rst) 25 | begin 26 | if rst = '1' then 27 | output <= (others => '0'); 28 | elsif rising_edge(clk) then 29 | if vld_in1 = '1' then 30 | output <= std_logic_vector(resize(unsigned(in1), width+1) - resize(unsigned(in2), width+1)); 31 | end if; 32 | end if; 33 | end process; 34 | end BHV; 35 | -------------------------------------------------------------------------------- /VHDL/add_pipe.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | entity add_pipe is 6 | generic ( 7 | width1 : positive := 16; 8 | width2 : positive := 16); 9 | port ( 10 | clk : in std_logic; 11 | rst : in std_logic; 12 | vld_in1 : in std_logic; 13 | in1 : in std_logic_vector(width1-1 downto 0); 14 | in2 : in std_logic_vector(width2-1 downto 0); 15 | output : out std_logic_vector(width1 downto 0)); 16 | end add_pipe; 17 | 18 | -- TODO: Implement a behavioral description of a pipelined adder (i.e., an 19 | -- adder with a register on the output). The output should be one bit larger 20 | -- than the input, and should use the "width" generic as opposed to being 21 | -- hardcoded to a specific value. 22 | 23 | architecture BHV of add_pipe is 24 | begin 25 | process(clk, rst) 26 | begin 27 | if rst = '1' then 28 | output <= (others => '0'); 29 | elsif rising_edge(clk) then 30 | if vld_in1 = '1' then 31 | output <= std_logic_vector(resize(signed(in1), width1+1) + resize(signed(in2), width1+1)); 32 | end if; 33 | end if; 34 | end process; 35 | end BHV; 36 | -------------------------------------------------------------------------------- /VHDL/ip_address_generator_1.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | use work.config_pkg.all; 5 | 6 | entity ip_address_generator_prow is 7 | port ( 8 | clk : in std_logic; 9 | rst : in std_logic; 10 | en : in std_logic; 11 | --size : in std_logic_vector(C_MEM_ADDR_WIDTH downto 0); 12 | add_out : out std_logic_vector(C_MEM_ADDR_WIDTH-1 downto 0)); 13 | end ip_address_generator_prow; 14 | 15 | architecture address of ip_address_generator_prow is 16 | signal increment : std_logic_vector(C_MEM_ADDR_WIDTH downto 0) := (0 => '1', others => '0'); 17 | 18 | begin 19 | process(clk, rst) 20 | variable gen_addr : std_logic_vector(C_MEM_ADDR_WIDTH downto 0) := (others => '0'); 21 | variable size_count : std_logic_vector(C_MEM_ADDR_WIDTH downto 0); 22 | begin 23 | size_count := std_logic_vector(to_unsigned(C_TOTAL_GROUPS, C_MEM_ADDR_WIDTH+1)); 24 | if rst = '1' then 25 | add_out <= (others => '0'); 26 | gen_addr := (others => '0'); 27 | elsif rising_edge(clk) then 28 | if en = '1' then 29 | gen_addr := std_logic_vector(unsigned(gen_addr) + unsigned(increment)); 30 | if gen_addr <= size_count then 31 | add_out <= gen_addr(C_MEM_ADDR_WIDTH-1 downto 0); 32 | end if; 33 | else 34 | add_out <= (others => '0'); 35 | gen_addr := gen_addr; 36 | end if; 37 | end if; 38 | end process; 39 | end address; 40 | -------------------------------------------------------------------------------- /VHDL/config_pkg.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | package config_pkg is 6 | 7 | constant C_MMAP_ADDR_WIDTH : positive := 18; 8 | constant C_MMAP_DATA_WIDTH : positive := 32; 9 | 10 | subtype MMAP_ADDR_RANGE is natural range C_MMAP_ADDR_WIDTH-1 downto 0; 11 | subtype MMAP_DATA_RANGE is natural range C_MMAP_DATA_WIDTH-1 downto 0; 12 | 13 | constant C_MEM_ADDR_WIDTH : positive := 15; 14 | constant C_MEM_IN_WIDTH : positive := 32; 15 | constant C_MEM_OUT_WIDTH : positive := 32; 16 | constant C_ELEMENT_COUNT : positive := 4; 17 | constant C_COLUMN_COUNT : positive := 32; --7; --32; 18 | constant C_TOTAL_GROUPS : positive := 4096; --896; --4096; 19 | 20 | constant C_MEM_START_ADDR : std_logic_vector(MMAP_ADDR_RANGE) := (others => '0'); 21 | constant C_MEM_END_ADDR : std_logic_vector(MMAP_ADDR_RANGE) := std_logic_vector(unsigned(C_MEM_START_ADDR)+(2**C_MEM_ADDR_WIDTH-1)); 22 | 23 | constant C_GO_ADDR : std_logic_vector(MMAP_ADDR_RANGE) := std_logic_vector(to_unsigned(2**C_MMAP_ADDR_WIDTH-3, C_MMAP_ADDR_WIDTH)); 24 | constant C_SIZE_ADDR : std_logic_vector(MMAP_ADDR_RANGE) := std_logic_vector(to_unsigned(2**C_MMAP_ADDR_WIDTH-2, C_MMAP_ADDR_WIDTH)); 25 | constant C_DONE_ADDR : std_logic_vector(MMAP_ADDR_RANGE) := std_logic_vector(to_unsigned(2**C_MMAP_ADDR_WIDTH-1, C_MMAP_ADDR_WIDTH)); 26 | 27 | constant C_1 : std_logic := '1'; 28 | constant C_0 : std_logic := '0'; 29 | 30 | end config_pkg; 31 | -------------------------------------------------------------------------------- /VHDL/ip_address_generator_3.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | use work.config_pkg.all; 5 | 6 | entity ip_address_generator_nrow is 7 | port ( 8 | clk : in std_logic; 9 | rst : in std_logic; 10 | en : in std_logic; 11 | --size : in std_logic_vector(C_MEM_ADDR_WIDTH downto 0); 12 | add_out : out std_logic_vector(C_MEM_ADDR_WIDTH-1 downto 0)); 13 | end ip_address_generator_nrow; 14 | 15 | architecture address of ip_address_generator_nrow is 16 | signal increment : std_logic_vector(C_MEM_ADDR_WIDTH downto 0) := (0 => '1', others => '0'); 17 | begin 18 | process(clk, rst) 19 | variable gen_addr : std_logic_vector(C_MEM_ADDR_WIDTH downto 0) := std_logic_vector(to_unsigned(2*C_COLUMN_COUNT, C_MEM_ADDR_WIDTH+1)); 20 | variable size_count : std_logic_vector(C_MEM_ADDR_WIDTH downto 0); 21 | begin 22 | size_count := std_logic_vector(to_unsigned(C_TOTAL_GROUPS+(2*C_COLUMN_COUNT), C_MEM_ADDR_WIDTH+1)); 23 | if rst = '1' then 24 | add_out <= (others => '0'); 25 | gen_addr := gen_addr; 26 | elsif rising_edge(clk) then 27 | if en = '1' then 28 | gen_addr := std_logic_vector(unsigned(gen_addr) + unsigned(increment)); 29 | if gen_addr <= size_count then 30 | add_out <= gen_addr(C_MEM_ADDR_WIDTH-1 downto 0); 31 | end if; 32 | else 33 | add_out <= (others => '0'); 34 | gen_addr := gen_addr; 35 | end if; 36 | end if; 37 | end process; 38 | end address; 39 | -------------------------------------------------------------------------------- /VHDL/op_address_generator.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | use work.config_pkg.all; 5 | 6 | entity op_address_generator is 7 | port ( 8 | clk : in std_logic; 9 | rst : in std_logic; 10 | en : in std_logic; 11 | --size : in std_logic_vector(C_MEM_ADDR_WIDTH downto 0); 12 | add_out : out std_logic_vector(C_MEM_ADDR_WIDTH-1 downto 0); 13 | endstream : out std_logic); 14 | end op_address_generator; 15 | 16 | architecture address of op_address_generator is 17 | signal increment : std_logic_vector(C_MEM_ADDR_WIDTH downto 0) := (0 => '1', others => '0'); 18 | begin 19 | process(clk, rst) 20 | variable gen_addr : std_logic_vector(C_MEM_ADDR_WIDTH downto 0) := (others => '0'); 21 | variable size_count : std_logic_vector(C_MEM_ADDR_WIDTH downto 0); 22 | begin 23 | size_count := std_logic_vector(to_unsigned(C_TOTAL_GROUPS, C_MEM_ADDR_WIDTH+1)); 24 | if rst = '1' then 25 | add_out <= (others => '0'); 26 | gen_addr := (others => '0'); 27 | endstream <= '0'; 28 | elsif rising_edge(clk) then 29 | if en = '1' then 30 | gen_addr := std_logic_vector(unsigned(gen_addr) + unsigned(increment)); 31 | if gen_addr < size_count then 32 | add_out <= gen_addr(14 downto 0); 33 | endstream <= '0'; 34 | else 35 | endstream <= '1'; 36 | end if; 37 | else 38 | add_out <= (others => '0'); 39 | gen_addr := (others => '0'); 40 | endstream <= '0'; 41 | end if; 42 | end if; 43 | end process; 44 | end address; 45 | -------------------------------------------------------------------------------- /VHDL/ip_address_generator_2.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | use work.config_pkg.all; 5 | 6 | entity ip_address_generator_crow is 7 | port ( 8 | clk : in std_logic; 9 | rst : in std_logic; 10 | en : in std_logic; 11 | --size : in std_logic_vector(C_MEM_ADDR_WIDTH downto 0); 12 | add_out : out std_logic_vector(C_MEM_ADDR_WIDTH-1 downto 0); 13 | vld_out : out std_logic); 14 | end ip_address_generator_crow; 15 | 16 | architecture address of ip_address_generator_crow is 17 | signal increment : std_logic_vector(C_MEM_ADDR_WIDTH downto 0) := (0 => '1', others => '0'); 18 | begin 19 | process(clk, rst) 20 | variable gen_addr : std_logic_vector(C_MEM_ADDR_WIDTH downto 0) := std_logic_vector(to_unsigned(C_COLUMN_COUNT, C_MEM_ADDR_WIDTH+1)); 21 | variable size_count : std_logic_vector(C_MEM_ADDR_WIDTH downto 0); 22 | begin 23 | size_count := std_logic_vector(to_unsigned(C_TOTAL_GROUPS+C_COLUMN_COUNT, C_MEM_ADDR_WIDTH+1)); 24 | if rst = '1' then 25 | add_out <= (others => '0'); 26 | gen_addr := gen_addr; 27 | vld_out <= '0'; 28 | elsif rising_edge(clk) then 29 | if en = '1' then 30 | gen_addr := std_logic_vector(unsigned(gen_addr) + unsigned(increment)); 31 | if gen_addr <= size_count then 32 | add_out <= gen_addr(C_MEM_ADDR_WIDTH-1 downto 0); 33 | vld_out <= '1'; 34 | else 35 | vld_out <= '0'; 36 | end if; 37 | else 38 | add_out <= (others => '0'); 39 | gen_addr := gen_addr; 40 | vld_out <= '0'; 41 | end if; 42 | end if; 43 | end process; 44 | end address; 45 | -------------------------------------------------------------------------------- /CPP/Board.h: -------------------------------------------------------------------------------- 1 | // Board class 2 | // This class implements a number of methods for interfacing with the FPGA. For the ZedBoard, this "board" is just the programmable logic section, but the class maintains the board analogy for use with other FPGAs that are on a separate board. 3 | 4 | #ifndef _BOARD_H_ 5 | #define _BOARD_H_ 6 | 7 | #include 8 | #include 9 | 10 | // starting address of AXI memory map 11 | #define AXI_MMAP_ADDR 0x43c00000 12 | 13 | // total size in bytes of memory-map address space 14 | #define MEM_INT_ADDR_SPACE (1 << 20) 15 | 16 | // total size in words of memory-map address psace 17 | #define MMAP_ADDR_WIDTH 18 18 | 19 | // bit width of each memory-map word 20 | #define MMAP_DATA_WIDTH 32 21 | 22 | enum MemId { 23 | MEM_INTERNAL, 24 | MEM_LAST // this is an invalid memory and is used for bounds checking only 25 | }; 26 | 27 | 28 | class Board { 29 | 30 | public: 31 | Board(const char *bitfile, const std::vector &frequencies); 32 | virtual ~Board(); 33 | 34 | virtual bool write(unsigned *data, unsigned long addr, unsigned long words); 35 | virtual bool read(unsigned *data, unsigned long addr, unsigned long words); 36 | 37 | // number of bytes in a page 38 | const unsigned PAGE_SIZE; 39 | 40 | static const unsigned NUM_FPGA_CLOCKS = 4; 41 | 42 | protected: 43 | 44 | // pointer to each page used in the memory-mapped AXI address space. 45 | unsigned **mmapPages; 46 | 47 | void copy(const char *to, const char *from); 48 | void loadBitfile(const char* bitfile); 49 | void writeToDriver(std::string file, std::string data) const; 50 | std::string readFromDriver(std::string file) const; 51 | void configureFpgaClock(unsigned clk, double freq); 52 | void configureFpgaClocks(const std::vector &frequencies); 53 | void initializeMemoryMap(); 54 | void handleError(std::string str) const; 55 | }; 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /VHDL/threshold_comp.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | entity thres_comp is 6 | generic ( 7 | width : positive := 8); 8 | port ( 9 | clk : in std_logic; 10 | rst : in std_logic; 11 | vld_in : in std_logic; 12 | input_p1 : in std_logic_vector((width)-1 downto 0); 13 | input_p2 : in std_logic_vector((width)-1 downto 0); 14 | input_p3 : in std_logic_vector((width)-1 downto 0); 15 | input_q1 : in std_logic_vector((width)-1 downto 0); 16 | input_q2 : in std_logic_vector((width)-1 downto 0); 17 | input_q3 : in std_logic_vector((width)-1 downto 0); 18 | input_r1 : in std_logic_vector((width)-1 downto 0); 19 | input_r2 : in std_logic_vector((width)-1 downto 0); 20 | input_r3 : in std_logic_vector((width)-1 downto 0); 21 | result : out std_logic_vector(7 downto 0)); 22 | end thres_comp; 23 | 24 | architecture BHV of thres_comp is 25 | signal threshold2 : std_logic_vector (7 downto 0) := "10110010"; 26 | signal threshold1 : std_logic_vector (7 downto 0) := "00111010"; 27 | begin 28 | process(clk, rst) 29 | begin 30 | if (rst = '1') then 31 | result <= (others => '0'); 32 | elsif (clk'event and clk = '1') then 33 | if (vld_in = '1') then 34 | if(unsigned(input_q2) >= unsigned(threshold2)) then 35 | result <= "11111111"; 36 | elsif(unsigned(input_q2) <= unsigned(threshold1)) then 37 | result <= "00000000"; 38 | elsif(unsigned(input_p1) >= unsigned(threshold2) or unsigned(input_p2) >= unsigned(threshold2) or unsigned(input_p3) >= unsigned(threshold2) or unsigned(input_q1) >= unsigned(threshold2) or unsigned(input_q3) >= unsigned(threshold2) or unsigned(input_r1) >= unsigned(threshold2) or unsigned(input_r2) >= unsigned(threshold2) or unsigned(input_r3) >= unsigned(threshold2)) then 39 | result <= "11111111"; 40 | else 41 | result <= "00000000"; 42 | end if; 43 | end if; 44 | end if; 45 | end process; 46 | end BHV; -------------------------------------------------------------------------------- /VHDL/datapath_thresh.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | entity datapath_threshold is 6 | generic ( 7 | width : positive := 8); 8 | port ( 9 | clk : in std_logic; 10 | rst : in std_logic; 11 | mag : in std_logic_vector(14 downto 0); 12 | input_prev : in std_logic_vector((3*width)-1 downto 0); 13 | input_curr : in std_logic_vector((3*width)-1 downto 0); 14 | input_next : in std_logic_vector((3*width)-1 downto 0); 15 | vld_in : in std_logic; 16 | vld_out : out std_logic; 17 | result : out std_logic_vector(7 downto 0)); 18 | end datapath_threshold; 19 | 20 | architecture pipe_datapath of datapath_threshold is 21 | 22 | signal reg1_out, reg2_out, reg3_out, reg4_out, reg5_out, reg6_out, reg7_out, reg8_out, reg9_out : std_logic_vector(width-1 downto 0); 23 | signal vld1 : std_logic; 24 | 25 | begin 26 | REG1 : entity work.reg generic map(width) port map(clk, rst, vld_in, input_prev((3*width)-1 downto 2*width), reg1_out); 27 | REG2 : entity work.reg generic map(width) port map(clk, rst, vld_in, input_prev((2*width)-1 downto width), reg2_out); 28 | REG3 : entity work.reg generic map(width) port map(clk, rst, vld_in, input_prev(width-1 downto 0), reg3_out); 29 | REG4 : entity work.reg generic map(width) port map(clk, rst, vld_in, input_curr((3*width)-1 downto 2*width), reg4_out); 30 | REG5 : entity work.reg generic map(width) port map(clk, rst, vld_in, mag, reg5_out); 31 | REG6 : entity work.reg generic map(width) port map(clk, rst, vld_in, input_curr(width-1 downto 0), reg6_out); 32 | REG7 : entity work.reg generic map(width) port map(clk, rst, vld_in, input_next((3*width)-1 downto 2*width), reg7_out); 33 | REG8 : entity work.reg generic map(width) port map(clk, rst, vld_in, input_next((2*width)-1 downto width), reg8_out); 34 | REG9 : entity work.reg generic map(width) port map(clk, rst, vld_in, input_next(width-1 downto 0), reg9_out); 35 | 36 | REGV1 : entity work.regbit port map(clk, rst, '1', vld_in, vld1); 37 | REGV2 : entity work.regbit port map(clk, rst, '1', vld1, vld_out); 38 | 39 | THRESHOLD_COMPARATOR : entity work.thres_comp generic map(width) port map(clk, rst, vld1, reg1_out, reg2_out, reg3_out, reg4_out, reg5_out, reg6_out, reg7_out, reg8_out,reg9_out, result); 40 | 41 | end pipe_datapath; -------------------------------------------------------------------------------- /VHDL/smartBuffer.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | use work.config_pkg.all; 5 | 6 | entity smart_buff is 7 | generic (width : positive := 32; outputWidth : positive := 48); 8 | port ( 9 | clk : in std_logic; 10 | rst : in std_logic; 11 | en : in std_logic; 12 | input : in std_logic_vector(width-1 downto 0); 13 | output : out std_logic_vector(outputWidth-1 downto 0) 14 | ); 15 | end smart_buff; 16 | 17 | architecture BHV of smart_buff is 18 | signal state : std_logic_vector(2 downto 0); 19 | signal sbuffer : std_logic_vector((2*width)-1 downto 0); 20 | signal zero : std_logic_vector(width-1 downto 0) := (others => '0'); 21 | 22 | begin 23 | process(clk, rst) 24 | begin 25 | if rst = '1' then 26 | state <= "000"; 27 | output <= (others => '0'); 28 | sbuffer <= (others => '0'); 29 | elsif rising_edge(clk) then 30 | if state = "000" then 31 | if en = '1' then 32 | state <= "001"; 33 | output <= (others => '0'); 34 | sbuffer <= zero & input; 35 | end if; 36 | elsif state = "001" then 37 | state <= "010"; 38 | output <= (others => '0'); 39 | sbuffer <= sbuffer(width-1 downto 0) & input; 40 | elsif state = "010" then 41 | if en = '0' then 42 | state <= "100"; 43 | output <= sbuffer((2*width)-1 downto (2*width)-outputWidth); 44 | sbuffer <= sbuffer(width-1 downto 0) & zero; 45 | else 46 | state <= "011"; 47 | output <= sbuffer((2*width)-1 downto (2*width)-outputWidth); 48 | sbuffer <= sbuffer(width-1 downto 0) & input; 49 | end if; 50 | elsif state = "011" then 51 | if en = '0' then 52 | state <= "100"; 53 | output <= sbuffer((2*width)-1 downto (2*width)-outputWidth); 54 | sbuffer <= sbuffer(width-1 downto 0) & zero; 55 | else 56 | state <= "011"; 57 | output <= sbuffer((2*width)-1 downto (2*width)-outputWidth); 58 | sbuffer <= sbuffer(width-1 downto 0) & input; 59 | end if; 60 | elsif state = "100" then 61 | state <= "101"; 62 | output <= sbuffer((2*width)-1 downto (2*width)-outputWidth); 63 | sbuffer <= sbuffer(width-1 downto 0) & zero; 64 | elsif state = "101" then 65 | state <= "000"; 66 | output <= (others => '0'); 67 | sbuffer <= (others => '0'); 68 | else 69 | state <= "000"; 70 | output <= (others => '0'); 71 | sbuffer <= (others => '0'); 72 | end if; 73 | end if; 74 | end process; 75 | end BHV; 76 | -------------------------------------------------------------------------------- /VHDL/smartBufferV.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | use work.config_pkg.all; 5 | 6 | 7 | entity smart_buff_v is 8 | generic (width : positive := 32; outputWidth : positive := 48); 9 | port ( 10 | clk : in std_logic; 11 | rst : in std_logic; 12 | en : in std_logic; 13 | input : in std_logic_vector(width-1 downto 0); 14 | valid : out std_logic; 15 | output : out std_logic_vector(outputWidth-1 downto 0) 16 | ); 17 | end smart_buff_v; 18 | 19 | architecture BHV of smart_buff_v is 20 | signal state : std_logic_vector(2 downto 0); 21 | signal sbuffer : std_logic_vector((2*width)-1 downto 0); 22 | signal zero : std_logic_vector(width-1 downto 0) := (others => '0'); 23 | 24 | begin 25 | process(clk, rst) 26 | begin 27 | if rst = '1' then 28 | state <= "000"; 29 | valid <= '0'; 30 | output <= (others => '0'); 31 | sbuffer <= (others => '0'); 32 | elsif rising_edge(clk) then 33 | if state = "000" then 34 | if en = '1' then 35 | state <= "001"; 36 | valid <= '0'; 37 | output <= (others => '0'); 38 | sbuffer <= zero & input; 39 | end if; 40 | elsif state = "001" then 41 | state <= "010"; 42 | valid <= '0'; 43 | output <= (others => '0'); 44 | sbuffer <= sbuffer(width-1 downto 0) & input; 45 | elsif state = "010" then 46 | if en = '0' then 47 | state <= "100"; 48 | valid <= '1'; 49 | output <= sbuffer((2*width)-1 downto (2*width)-outputWidth); 50 | sbuffer <= sbuffer(width-1 downto 0) & zero; 51 | else 52 | state <= "011"; 53 | valid <= '1'; 54 | output <= sbuffer((2*width)-1 downto (2*width)-outputWidth); 55 | sbuffer <= sbuffer(width-1 downto 0) & input; 56 | end if; 57 | elsif state = "011" then 58 | if en = '0' then 59 | state <= "100"; 60 | valid <= '1'; 61 | output <= sbuffer((2*width)-1 downto (2*width)-outputWidth); 62 | sbuffer <= sbuffer(width-1 downto 0) & zero; 63 | else 64 | state <= "011"; 65 | valid <= '1'; 66 | output <= sbuffer((2*width)-1 downto (2*width)-outputWidth); 67 | sbuffer <= sbuffer(width-1 downto 0) & input; 68 | end if; 69 | elsif state = "100" then 70 | state <= "101"; 71 | valid <= '1'; 72 | output <= sbuffer((2*width)-1 downto (2*width)-outputWidth); 73 | sbuffer <= sbuffer(width-1 downto 0) & zero; 74 | elsif state = "101" then 75 | state <= "000"; 76 | valid <= '0'; 77 | output <= (others => '0'); 78 | sbuffer <= (others => '0'); 79 | else 80 | state <= "000"; 81 | valid <= '0'; 82 | output <= (others => '0'); 83 | sbuffer <= (others => '0'); 84 | end if; 85 | end if; 86 | end process; 87 | end BHV; 88 | -------------------------------------------------------------------------------- /VHDL/datapathGy.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | entity datapath_gy is 6 | generic ( 7 | width : positive := 8); 8 | port ( 9 | clk : in std_logic; 10 | rst : in std_logic; 11 | input_prev : in std_logic_vector((3*width)-1 downto 0); 12 | input_next : in std_logic_vector((3*width)-1 downto 0); 13 | sob_coeff1 : in std_logic_vector(1 downto 0); 14 | sob_coeff2 : in std_logic_vector(1 downto 0); 15 | vld_in : in std_logic; 16 | vld_out : out std_logic; 17 | result : out std_logic_vector(width+4 downto 0)); 18 | end datapath_gy; 19 | 20 | architecture pipe_datapath of datapath_gy is 21 | signal mult1_out, mult2_out, mult3_out, mult4_out, mult5_out, mult6_out : std_logic_vector(width+1 downto 0); 22 | signal reg1_out, reg2_out, reg3_out, reg4_out, reg5_out, reg6_out : std_logic_vector(width-1 downto 0); 23 | signal vld1, vld2, vld3, vld4 : std_logic; 24 | signal sub1_out, sub2_out, sub3_out, sub3_out1 : std_logic_vector(width+2 downto 0); 25 | signal add1_out : std_logic_vector(width+3 downto 0); 26 | 27 | begin 28 | REG1 : entity work.reg generic map(width) port map(clk, rst, vld_in, input_prev((3*width)-1 downto 2*width), reg1_out); 29 | REG2 : entity work.reg generic map(width) port map(clk, rst, vld_in, input_prev((2*width)-1 downto width), reg2_out); 30 | REG3 : entity work.reg generic map(width) port map(clk, rst, vld_in, input_prev(width-1 downto 0), reg3_out); 31 | REG4 : entity work.reg generic map(width) port map(clk, rst, vld_in, input_next((3*width)-1 downto 2*width), reg4_out); 32 | REG5 : entity work.reg generic map(width) port map(clk, rst, vld_in, input_next((2*width)-1 downto width), reg5_out); 33 | REG6 : entity work.reg generic map(width) port map(clk, rst, vld_in, input_next(width-1 downto 0), reg6_out); 34 | 35 | REGV1 : entity work.regbit port map(clk, rst, '1', vld_in, vld1); 36 | REGV2 : entity work.regbit port map(clk, rst, '1', vld1, vld2); 37 | REGV3 : entity work.regbit port map(clk, rst, '1', vld2, vld3); 38 | REGV4 : entity work.regbit port map(clk, rst, '1', vld3, vld4); 39 | REGV5 : entity work.regbit port map(clk, rst, '1', vld4, vld_out); 40 | 41 | MULT1 : entity work.mult_pipe generic map(width, 2) port map(clk, rst, vld1, reg1_out, sob_coeff1, mult1_out); 42 | MULT2 : entity work.mult_pipe generic map(width, 2) port map(clk, rst, vld1, reg2_out, sob_coeff2, mult2_out); 43 | MULT3 : entity work.mult_pipe generic map(width, 2) port map(clk, rst, vld1, reg3_out, sob_coeff1, mult3_out); 44 | MULT4 : entity work.mult_pipe generic map(width, 2) port map(clk, rst, vld1, reg4_out, sob_coeff1, mult4_out); 45 | MULT5 : entity work.mult_pipe generic map(width, 2) port map(clk, rst, vld1, reg5_out, sob_coeff2, mult5_out); 46 | MULT6 : entity work.mult_pipe generic map(width, 2) port map(clk, rst, vld1, reg6_out, sob_coeff1, mult6_out); 47 | 48 | SUB1 : entity work.sub_pipe generic map(width+2) port map(clk, rst, vld2, mult1_out, mult4_out, sub1_out); 49 | SUB2 : entity work.sub_pipe generic map(width+2) port map(clk, rst, vld2, mult2_out, mult5_out, sub2_out); 50 | SUB3 : entity work.sub_pipe generic map(width+2) port map(clk, rst, vld2, mult3_out, mult6_out, sub3_out); 51 | 52 | ADD1 : entity work.add_pipe generic map(width+3, width+3) port map(clk, rst, vld3, sub1_out, sub2_out, add1_out); 53 | REG7 : entity work.reg generic map(width+3) port map(clk, rst, vld3, sub3_out, sub3_out1); 54 | 55 | ADD2 : entity work.add_pipe generic map(width+4, width+3) port map(clk, rst, vld4, add1_out, sub3_out1, result); 56 | end pipe_datapath; 57 | -------------------------------------------------------------------------------- /VHDL/memory_map.vhd: -------------------------------------------------------------------------------- 1 | -- Entity: memory_map 2 | -- This entity establishes connections with user-defined addresses and 3 | -- internal FPGA components (e.g. registers and blockRAMs). 4 | -- 5 | -- Note: Make sure to add any new addresses to user_pkg. Also, in your C code, 6 | -- make sure to use the same constants. 7 | 8 | library ieee; 9 | use ieee.std_logic_1164.all; 10 | use ieee.numeric_std.all; 11 | 12 | use work.config_pkg.all; 13 | --use work.user_pkg.all; 14 | 15 | entity memory_map is 16 | port ( 17 | clk : in std_logic; 18 | rst : in std_logic; 19 | wr_en : in std_logic; 20 | wr_addr : in std_logic_vector(MMAP_ADDR_RANGE); 21 | wr_data : in std_logic_vector(MMAP_DATA_RANGE); 22 | rd_en : in std_logic; 23 | rd_addr : in std_logic_vector(MMAP_ADDR_RANGE); 24 | rd_data : out std_logic_vector(MMAP_DATA_RANGE); 25 | 26 | -- app-specific signals 27 | go : out std_logic; 28 | size : out std_logic_vector(C_MEM_ADDR_WIDTH downto 0); 29 | done : in std_logic; 30 | mem_in_wr_data : out std_logic_vector(C_MEM_IN_WIDTH-1 downto 0); 31 | mem_in_wr_addr : out std_logic_vector(C_MEM_ADDR_WIDTH-1 downto 0); 32 | mem_in_wr_en : out std_logic; 33 | mem_out_rd_data : in std_logic_vector(C_MEM_OUT_WIDTH-1 downto 0); 34 | mem_out_rd_addr : out std_logic_vector(C_MEM_ADDR_WIDTH-1 downto 0) 35 | ); 36 | end memory_map; 37 | 38 | architecture BHV of memory_map is 39 | 40 | signal reg_go : std_logic; 41 | signal reg_size : std_logic_vector(C_MEM_ADDR_WIDTH downto 0); 42 | signal reg_rd_data : std_logic_vector(C_MMAP_DATA_WIDTH-1 downto 0); 43 | signal rd_data_sel : std_logic; 44 | 45 | constant C_RD_DATA_SEL_REG : std_logic := '0'; 46 | constant C_RD_DATA_SEL_MEM_OUT : std_logic := '1'; 47 | begin 48 | 49 | mem_in_wr_data <= wr_data(mem_in_wr_data'range); 50 | mem_in_wr_addr <= wr_addr(mem_in_wr_addr'range); 51 | mem_in_wr_en <= '1' when wr_en = '1' and unsigned(wr_addr) >= unsigned(C_MEM_START_ADDR) and unsigned(wr_addr) <= unsigned(C_MEM_END_ADDR) else '0'; 52 | 53 | mem_out_rd_addr <= rd_addr(mem_out_rd_addr'range); 54 | 55 | process(clk, rst) 56 | begin 57 | if (rst = '1') then 58 | reg_go <= '0'; 59 | reg_size <= (others => '0'); 60 | rd_data_sel <= '0'; 61 | reg_rd_data <= (others => '0'); 62 | 63 | elsif (rising_edge(clk)) then 64 | 65 | reg_go <= '0'; 66 | 67 | if (wr_en = '1') then 68 | 69 | case wr_addr is 70 | when C_GO_ADDR => 71 | reg_go <= wr_data(0); 72 | when C_SIZE_ADDR => 73 | reg_size <= wr_data(reg_size'range); 74 | when others => null; 75 | end case; 76 | end if; 77 | 78 | if (rd_en = '1') then 79 | 80 | rd_data_sel <= C_RD_DATA_SEL_REG; 81 | reg_rd_data <= (others => '0'); 82 | 83 | -- check if rd_addr corresponds to memory or registers 84 | if (unsigned(rd_addr) > unsigned(C_MEM_END_ADDR)) then 85 | rd_data_sel <= C_RD_DATA_SEL_REG; 86 | else 87 | rd_data_sel <= C_RD_DATA_SEL_MEM_OUT; 88 | end if; 89 | 90 | -- select the appropriate register for a read 91 | case rd_addr is 92 | when C_GO_ADDR => 93 | reg_rd_data <= std_logic_vector(to_unsigned(0, C_MMAP_DATA_WIDTH-1)) & reg_go; 94 | when C_SIZE_ADDR => 95 | reg_rd_data <= (others => '0'); 96 | reg_rd_data(reg_size'range) <= reg_size; 97 | when C_DONE_ADDR => 98 | reg_rd_data <= std_logic_vector(to_unsigned(0, C_MMAP_DATA_WIDTH-1)) & done; 99 | when others => null; 100 | end case; 101 | end if; 102 | 103 | end if; 104 | end process; 105 | 106 | go <= reg_go; 107 | size <= reg_size; 108 | 109 | -- mux that defines dout based on where the read data come from 110 | process(rd_data_sel, reg_rd_data, mem_out_rd_data) 111 | begin 112 | rd_data <= (others => '0'); 113 | 114 | case rd_data_sel is 115 | when C_RD_DATA_SEL_MEM_OUT => 116 | rd_data(mem_out_rd_data'range) <= mem_out_rd_data; 117 | when C_RD_DATA_SEL_REG => 118 | rd_data <= reg_rd_data; 119 | when others => null; 120 | end case; 121 | end process; 122 | 123 | end BHV; 124 | -------------------------------------------------------------------------------- /VHDL/op_ram.vhd: -------------------------------------------------------------------------------- 1 | -- Description: 2 | -- The ram entity implements a ram with a standard 1-read port, 1-write port 3 | -- interface. The ram is configurable in terms of data width (width of each 4 | -- word), the address width, and the number of words. The ram has a write 5 | -- enable for writes, but does not contain a read enable. Instead, the ram 6 | -- reads from the read address every cycle. 7 | -- 8 | -- The entity contains several different architectures that implement different 9 | -- ram behaviors. e.g. synchronous reads, asynchronous reads, synchronoous 10 | -- reads during writes. 11 | -- 12 | 13 | -- Notes: 14 | -- Asychronous reads are not supported by all FPGAs. 15 | -- 16 | 17 | ------------------------------------------------------------------------------- 18 | -- Generics Description 19 | -- word_width : The width in bits of a single word (required) 20 | -- addr_width : The width in bits of an address, which also defines the 21 | -- number of words (required) 22 | -- num_words : The number of words in the memory. This generic will 23 | -- usually be 2**addr_width, but the entity supports 24 | -- non-powers of 2 (required) 25 | ------------------------------------------------------------------------------- 26 | 27 | ------------------------------------------------------------------------------- 28 | -- Port Description: 29 | -- clk : clock input 30 | -- wen : write enable (active high) 31 | -- waddr : write address 32 | -- wdata : write data 33 | -- raddr : read address 34 | -- rdata : read data 35 | ------------------------------------------------------------------------------- 36 | 37 | 38 | library ieee; 39 | use ieee.std_logic_1164.all; 40 | use ieee.numeric_std.all; 41 | 42 | entity op_ram is 43 | generic ( 44 | num_words : positive; 45 | word_width : positive; 46 | addr_width : positive 47 | ); 48 | port ( 49 | clk : in std_logic; 50 | -- write port 51 | wen : in std_logic; 52 | waddr : in std_logic_vector(addr_width-1 downto 0); 53 | wdata : in std_logic_vector(word_width-1 downto 0); 54 | -- read port 55 | raddr : in std_logic_vector(addr_width-1 downto 0); 56 | rdata : out std_logic_vector(word_width-1 downto 0) 57 | ); 58 | end entity; 59 | 60 | 61 | -- This architecture uses asynchronous reads that return the read data in the 62 | -- same cycle. 63 | architecture ASYNC_READ of op_ram is 64 | 65 | type memory_type is array (natural range <>) of std_logic_vector(word_width-1 downto 0); 66 | signal memory : memory_type(num_words-1 downto 0) := (others => (others => '0')); 67 | 68 | begin 69 | 70 | process(clk) 71 | begin 72 | if clk'event and clk = '1' then 73 | if wen = '1' then 74 | memory(to_integer(unsigned(waddr))) <= wdata; 75 | end if; 76 | end if; 77 | end process; 78 | 79 | rdata <= memory(to_integer(unsigned(raddr))); 80 | 81 | end ASYNC_READ; 82 | 83 | 84 | -- This architecture uses synchronous reads with a one-cycle delay. In the case 85 | -- of reading and writing to the same address, the read returns the new data 86 | -- that was written. 87 | architecture SYNC_READ_DURING_WRITE of op_ram is 88 | 89 | type memory_type is array (natural range <>) of std_logic_vector(word_width-1 downto 0); 90 | signal memory : memory_type(num_words-1 downto 0) := (others => (others => '0')); 91 | signal raddr_reg : std_logic_vector(addr_width-1 downto 0); 92 | 93 | begin 94 | 95 | process(clk) 96 | begin 97 | if clk'event and clk = '1' then 98 | if wen = '1' then 99 | memory(to_integer(unsigned(waddr))) <= wdata; 100 | end if; 101 | 102 | raddr_reg <= raddr; 103 | end if; 104 | end process; 105 | 106 | rdata <= memory(to_integer(unsigned(raddr_reg))); 107 | 108 | end SYNC_READ_DURING_WRITE; 109 | 110 | 111 | -- This architecture uses synchronous reads with a one-cycle delay. In the case 112 | -- of reading and writing to the same address, the read returns the data at 113 | -- the address before the write. 114 | architecture SYNC_READ of op_ram is 115 | 116 | type memory_type is array (natural range <>) of std_logic_vector(word_width-1 downto 0); 117 | signal memory : memory_type(num_words-1 downto 0) := (others => (others => '0')); 118 | 119 | begin 120 | 121 | process(clk) 122 | begin 123 | if clk'event and clk = '1' then 124 | if wen = '1' then 125 | memory(to_integer(unsigned(waddr))) <= wdata; 126 | end if; 127 | 128 | rdata <= memory(to_integer(unsigned(raddr))); 129 | end if; 130 | end process; 131 | 132 | end SYNC_READ; 133 | -------------------------------------------------------------------------------- /VHDL/datapathGx.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | entity datapathGx is 6 | generic ( 7 | width : positive := 8); 8 | port ( 9 | clk : in std_logic; 10 | rst : in std_logic; 11 | prev_row : in std_logic_vector(47 downto 0); 12 | curr_row : in std_logic_vector(47 downto 0); 13 | next_row : in std_logic_vector(47 downto 0); 14 | input_prev : in std_logic_vector((3*width)-1 downto 0); 15 | input_curr : in std_logic_vector((3*width)-1 downto 0); 16 | input_next : in std_logic_vector((3*width)-1 downto 0); 17 | sob_coeff1 : in std_logic_vector(1 downto 0); 18 | sob_coeff2 : in std_logic_vector(1 downto 0); 19 | vld_in : in std_logic; 20 | vld_out : out std_logic; 21 | result : out std_logic_vector(width+4 downto 0); 22 | out_prev_row : out std_logic_vector(89 downto 0); 23 | out_curr_row : out std_logic_vector(89 downto 0); 24 | out_next_row : out std_logic_vector(89 downto 0) 25 | ); 26 | end datapathGx; 27 | 28 | architecture pipe_datapath of datapathGx is 29 | signal mult1_out, mult2_out, mult3_out, mult4_out, mult5_out, mult6_out : std_logic_vector(width+1 downto 0); 30 | signal reg1_out, reg2_out, reg3_out, reg4_out, reg5_out, reg6_out : std_logic_vector(width-1 downto 0); 31 | signal vld1, vld2, vld3, vld4 : std_logic; 32 | signal sub1_out, sub2_out, sub3_out, sub3_out1 : std_logic_vector(width+2 downto 0); 33 | signal add1_out : std_logic_vector(width+3 downto 0); 34 | --signal datapath_op : std_logic_vector(width+4 downto 0); 35 | 36 | begin 37 | --result <= std_logic_vector(resize(unsigned(datapath_op), width)); 38 | REG1 : entity work.reg generic map(width) port map(clk, rst, vld_in, input_prev((3*width)-1 downto 2*width), reg1_out); 39 | REG2 : entity work.reg generic map(width) port map(clk, rst, vld_in, input_prev(width-1 downto 0), reg2_out); 40 | REG3 : entity work.reg generic map(width) port map(clk, rst, vld_in, input_curr((3*width)-1 downto 2*width), reg3_out); 41 | REG4 : entity work.reg generic map(width) port map(clk, rst, vld_in, input_curr(width-1 downto 0), reg4_out); 42 | REG5 : entity work.reg generic map(width) port map(clk, rst, vld_in, input_next((3*width)-1 downto 2*width), reg5_out); 43 | REG6 : entity work.reg generic map(width) port map(clk, rst, vld_in, input_next(width-1 downto 0), reg6_out); 44 | 45 | REGV1 : entity work.regbit port map(clk, rst, '1', vld_in, vld1); 46 | REGV2 : entity work.regbit port map(clk, rst, '1', vld1, vld2); 47 | REGV3 : entity work.regbit port map(clk, rst, '1', vld2, vld3); 48 | REGV4 : entity work.regbit port map(clk, rst, '1', vld3, vld4); 49 | REGV5 : entity work.regbit port map(clk, rst, '1', vld4, vld_out); 50 | 51 | MULT1 : entity work.mult_pipe generic map(width, 2) port map(clk, rst, vld1, reg1_out, sob_coeff1, mult1_out); 52 | MULT2 : entity work.mult_pipe generic map(width, 2) port map(clk, rst, vld1, reg2_out, sob_coeff1, mult2_out); 53 | MULT3 : entity work.mult_pipe generic map(width, 2) port map(clk, rst, vld1, reg3_out, sob_coeff2, mult3_out); 54 | MULT4 : entity work.mult_pipe generic map(width, 2) port map(clk, rst, vld1, reg4_out, sob_coeff2, mult4_out); 55 | MULT5 : entity work.mult_pipe generic map(width, 2) port map(clk, rst, vld1, reg5_out, sob_coeff1, mult5_out); 56 | MULT6 : entity work.mult_pipe generic map(width, 2) port map(clk, rst, vld1, reg6_out, sob_coeff1, mult6_out); 57 | 58 | SUB1 : entity work.sub_pipe generic map(width+2) port map(clk, rst, vld2, mult2_out, mult1_out, sub1_out); 59 | SUB2 : entity work.sub_pipe generic map(width+2) port map(clk, rst, vld2, mult4_out, mult3_out, sub2_out); 60 | SUB3 : entity work.sub_pipe generic map(width+2) port map(clk, rst, vld2, mult6_out, mult5_out, sub3_out); 61 | 62 | ADD1 : entity work.add_pipe generic map(width+3, width+3) port map(clk, rst, vld3, sub1_out, sub2_out, add1_out); 63 | REG7 : entity work.reg generic map(width+3) port map(clk, rst, vld3, sub3_out, sub3_out1); 64 | 65 | ADD2 : entity work.add_pipe generic map(width+4, width+3) port map(clk, rst, vld4, add1_out, sub3_out1, result); 66 | -- process(vld4) 67 | -- begin 68 | --- if((vld4 = '1') and (clk'event and clk = '1')) then 69 | out_prev_row <= "0000000" & prev_row(47 downto 40) & "0000000" & prev_row(39 downto 32) 70 | & "0000000" & prev_row(31 downto 24) & "0000000" & prev_row(23 downto 16) 71 | & "0000000" & prev_row(15 downto 8) & "0000000" & prev_row(7 downto 0); 72 | out_curr_row <= "0000000" & curr_row(47 downto 40) & "0000000" & curr_row(39 downto 32) 73 | & "0000000" & curr_row(31 downto 24) & "0000000" & curr_row(23 downto 16) 74 | & "0000000" & curr_row(15 downto 8) & "0000000" & curr_row(7 downto 0); 75 | out_next_row <= "0000000" & next_row(47 downto 40) & "0000000" & next_row(39 downto 32) 76 | & "0000000" & next_row(31 downto 24) & "0000000" & next_row(23 downto 16) 77 | & "0000000" & next_row(15 downto 8) & "0000000" & next_row(7 downto 0); 78 | --- end if; 79 | --end process; 80 | end pipe_datapath; 81 | -------------------------------------------------------------------------------- /VHDL/ip_ram.vhd: -------------------------------------------------------------------------------- 1 | -- Description: 2 | -- The ram entity implements a ram with a 3-read port, 1-write port 3 | -- interface. The ram is configurable in terms of data width (width of each 4 | -- word), the address width, and the number of words. The ram has a write 5 | -- enable for writes, but does not contain a read enable. Instead, the ram 6 | -- reads from the read address every cycle. 7 | -- 8 | -- The entity contains several different architectures that implement different 9 | -- ram behaviors. e.g. synchronous reads, asynchronous reads, synchronoous 10 | -- reads during writes. 11 | -- 12 | 13 | -- Notes: 14 | -- Asychronous reads are not supported by all FPGAs. 15 | -- 16 | 17 | ------------------------------------------------------------------------------- 18 | -- Generics Description 19 | -- word_width : The width in bits of a single word (required) 20 | -- addr_width : The width in bits of an address, which also defines the 21 | -- number of words (required) 22 | -- num_words : The number of words in the memory. This generic will 23 | -- usually be 2**addr_width, but the entity supports 24 | -- non-powers of 2 (required) 25 | ------------------------------------------------------------------------------- 26 | 27 | ------------------------------------------------------------------------------- 28 | -- Port Description: 29 | -- clk : clock input 30 | -- wen : write enable (active high) 31 | -- waddr : write address 32 | -- wdata : write data 33 | -- raddr : read address 34 | -- rdata : read data 35 | ------------------------------------------------------------------------------- 36 | 37 | 38 | library ieee; 39 | use ieee.std_logic_1164.all; 40 | use ieee.numeric_std.all; 41 | 42 | entity ip_ram is 43 | generic ( 44 | num_words : positive; 45 | word_width : positive; 46 | addr_width : positive 47 | ); 48 | port ( 49 | clk : in std_logic; 50 | -- write port 51 | wen : in std_logic; 52 | waddr : in std_logic_vector(addr_width-1 downto 0); 53 | wdata : in std_logic_vector(word_width-1 downto 0); 54 | -- read ports 55 | raddr1 : in std_logic_vector(addr_width-1 downto 0); 56 | rdata1 : out std_logic_vector(word_width-1 downto 0); 57 | raddr2 : in std_logic_vector(addr_width-1 downto 0); 58 | rdata2 : out std_logic_vector(word_width-1 downto 0); 59 | raddr3 : in std_logic_vector(addr_width-1 downto 0); 60 | rdata3 : out std_logic_vector(word_width-1 downto 0) 61 | ); 62 | end entity; 63 | 64 | 65 | -- This architecture uses asynchronous reads that return the read data in the 66 | -- same cycle. 67 | architecture ASYNC_READ of ip_ram is 68 | 69 | type memory_type is array (natural range <>) of std_logic_vector(word_width-1 downto 0); 70 | signal memory : memory_type(num_words-1 downto 0) := (others => (others => '0')); 71 | 72 | begin 73 | 74 | process(clk) 75 | begin 76 | if clk'event and clk = '1' then 77 | if wen = '1' then 78 | memory(to_integer(unsigned(waddr))) <= wdata; 79 | end if; 80 | end if; 81 | end process; 82 | 83 | rdata1 <= memory(to_integer(unsigned(raddr1))); 84 | rdata2 <= memory(to_integer(unsigned(raddr2))); 85 | rdata3 <= memory(to_integer(unsigned(raddr3))); 86 | 87 | end ASYNC_READ; 88 | 89 | 90 | -- This architecture uses synchronous reads with a one-cycle delay. In the case 91 | -- of reading and writing to the same address, the read returns the new data 92 | -- that was written. 93 | architecture SYNC_READ_DURING_WRITE of ip_ram is 94 | 95 | type memory_type is array (natural range <>) of std_logic_vector(word_width-1 downto 0); 96 | signal memory : memory_type(num_words-1 downto 0) := (others => (others => '0')); 97 | signal raddr_reg1, raddr_reg2, raddr_reg3 : std_logic_vector(addr_width-1 downto 0); 98 | 99 | begin 100 | 101 | process(clk) 102 | begin 103 | if clk'event and clk = '1' then 104 | if wen = '1' then 105 | memory(to_integer(unsigned(waddr))) <= wdata; 106 | end if; 107 | 108 | raddr_reg1 <= raddr1; 109 | raddr_reg2 <= raddr2; 110 | raddr_reg3 <= raddr3; 111 | end if; 112 | end process; 113 | 114 | rdata1 <= memory(to_integer(unsigned(raddr_reg1))); 115 | rdata2 <= memory(to_integer(unsigned(raddr_reg2))); 116 | rdata3 <= memory(to_integer(unsigned(raddr_reg3))); 117 | 118 | end SYNC_READ_DURING_WRITE; 119 | 120 | 121 | -- This architecture uses synchronous reads with a one-cycle delay. In the case 122 | -- of reading and writing to the same address, the read returns the data at 123 | -- the address before the write. 124 | architecture SYNC_READ of ip_ram is 125 | 126 | type memory_type is array (natural range <>) of std_logic_vector(word_width-1 downto 0); 127 | signal memory : memory_type(num_words-1 downto 0) := (others => (others => '0')); 128 | 129 | begin 130 | 131 | process(clk) 132 | begin 133 | if clk'event and clk = '1' then 134 | if wen = '1' then 135 | memory(to_integer(unsigned(waddr))) <= wdata; 136 | end if; 137 | 138 | rdata1 <= memory(to_integer(unsigned(raddr1))); 139 | rdata2 <= memory(to_integer(unsigned(raddr2))); 140 | rdata3 <= memory(to_integer(unsigned(raddr3))); 141 | end if; 142 | end process; 143 | 144 | end SYNC_READ; 145 | -------------------------------------------------------------------------------- /CPP/Board.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "Board.h" 14 | 15 | using namespace std; 16 | 17 | #define CLK_EXPORT_FILE "/sys/devices/soc0/amba/f8007000.devcfg/fclk_export" 18 | #define CLK_BASE_PATH "/sys/devices/soc0/amba/f8007000.devcfg/fclk/" 19 | #define CLK_SET_RATE_FILE "set_rate" 20 | #define CLK_ENABLE_FILE "enable" 21 | #define CLK_NAME "fclk" 22 | 23 | /* 24 | #define CLK0_PATH "/sys/devices/soc0/amba/f8007000.devcfg/fclk/fclk0/set_rate" 25 | #define CLK0 "fclk0" 26 | #define CLK1 "fclk1" 27 | #define CLK2 "fclk2" 28 | #define CLK3 "fclk3" 29 | */ 30 | 31 | Board::Board(const char *bitfile, const vector &clocks) : PAGE_SIZE(sysconf(_SC_PAGESIZE)) { 32 | 33 | if (clocks.size() != NUM_FPGA_CLOCKS) { 34 | 35 | ostringstream errorMsg; 36 | errorMsg << "Error: clocks vector must have " << NUM_FPGA_CLOCKS << " frequencies."; 37 | handleError(errorMsg.str()); 38 | } 39 | 40 | // make sure unsigned is 4 bytes on this machine 41 | assert(sizeof(unsigned) == 4); 42 | 43 | configureFpgaClocks(clocks); 44 | loadBitfile(bitfile); 45 | initializeMemoryMap(); 46 | } 47 | 48 | 49 | Board::~Board() { 50 | 51 | delete mmapPages; 52 | } 53 | 54 | /* 55 | void Board::setClockStatus(unsigned clk, bool enable) { 56 | 57 | FILE *outFile; 58 | char value = enable ? 1 : 0; 59 | outFile = fopen(name.c_str(), "w"); 60 | if (outFile==NULL) {handleError("Error opening " + name);} 61 | fwrite(&value, sizeof(char), 1, outFile); 62 | fclose(outFile); 63 | } 64 | */ 65 | 66 | void Board::writeToDriver(string file, string data) const { 67 | 68 | FILE *outFile = fopen(file.c_str(), "w"); 69 | if (outFile==NULL) {handleError("Error opening " + file);} 70 | fwrite(data.c_str(), sizeof(char), data.size(), outFile); 71 | fclose(outFile); 72 | } 73 | 74 | string Board::readFromDriver(string file) const { 75 | 76 | FILE *inFile = fopen(file.c_str(), "rb" ); 77 | if (inFile==NULL) {handleError("Error opening " + file);} 78 | 79 | unsigned long fileSize; 80 | fseek(inFile , 0 , SEEK_END); 81 | fileSize = ftell(inFile); 82 | rewind(inFile); 83 | 84 | char *buffer = (char*) new char[fileSize]; 85 | unsigned long size = fread(buffer, sizeof(char), fileSize, inFile); 86 | fclose(inFile); 87 | 88 | string returnVal; 89 | returnVal.assign(buffer, size); 90 | delete buffer; 91 | return returnVal; 92 | } 93 | 94 | 95 | void Board::configureFpgaClock(unsigned clockId, double freq) { 96 | 97 | ostringstream name; 98 | ostringstream path; 99 | ostringstream freqFile; 100 | ostringstream enableFile; 101 | ostringstream freqData; 102 | string enableData; 103 | 104 | name << CLK_NAME << clockId; 105 | path << CLK_BASE_PATH << name.str() << "/"; 106 | freqFile << path.str() << CLK_SET_RATE_FILE; 107 | enableFile << path.str() << CLK_ENABLE_FILE; 108 | freqData << (int) (freq * 1000000); 109 | enableData = freq != 0.0 ? "1" : "0"; 110 | 111 | // printf("Configuring clock %d:\n", clockId); 112 | //printf("%s %s %s %s %s %s\n", name.str().c_str(), path.str().c_str(), freqFile.str().c_str(), enableFile.str().c_str(), freqData.str().c_str(), enableData.c_str()); 113 | 114 | // expose the corresponding clock drivers to the file system 115 | writeToDriver(CLK_EXPORT_FILE, name.str()); 116 | 117 | // enable/disable the corresponding clock 118 | writeToDriver(enableFile.str(), enableData); 119 | 120 | // set the clock frequency 121 | if (freq != 0.0) { 122 | 123 | writeToDriver(freqFile.str(), freqData.str()); 124 | } 125 | 126 | /* 127 | string debugFreq = readFromDriver(freqFile.str()); 128 | string debugEnable = readFromDriver(enableFile.str()); 129 | cout << "->" << debugFreq << "<-" << endl; 130 | cout << "->" << debugEnable << "<-" << endl; 131 | */ 132 | } 133 | 134 | 135 | void Board::configureFpgaClocks(const vector &clocks) { 136 | 137 | for (unsigned i=0; i < clocks.size(); i++) { 138 | 139 | configureFpgaClock(i, clocks[i]); 140 | } 141 | } 142 | 143 | 144 | void Board::copy(const char *to, const char *from) { 145 | 146 | FILE *inFile, *outFile; 147 | unsigned long lSize; 148 | char * buffer; 149 | size_t result; 150 | 151 | // open input file 152 | inFile = fopen(from, "rb" ); 153 | if (inFile==NULL) {handleError("Error opening " + (string) from);} 154 | 155 | // obtain file size: 156 | fseek (inFile , 0 , SEEK_END); 157 | lSize = ftell (inFile); 158 | rewind (inFile); 159 | 160 | // allocate memory to contain the whole file: 161 | buffer = (char*) malloc (sizeof(char)*lSize); 162 | if (buffer == NULL) {fputs ("Memory error",stderr); exit (2);} 163 | 164 | // copy the file into the buffer: 165 | result = fread (buffer,1,lSize,inFile); 166 | if (result != lSize) {handleError("Error reading " + (string) from);} 167 | 168 | // open and write to output file 169 | outFile = fopen (to, "w" ); 170 | if (outFile==NULL) {handleError("Error opening " + (string) to);} 171 | fwrite(buffer, sizeof(char), lSize, outFile); 172 | 173 | // terminate 174 | fclose(inFile); 175 | fclose(outFile); 176 | free(buffer); 177 | } 178 | 179 | 180 | void Board::loadBitfile(const char* bitfile) { 181 | 182 | copy("/dev/xdevcfg", bitfile); 183 | } 184 | 185 | 186 | void Board::initializeMemoryMap() { 187 | 188 | // Open /dev/mem file 189 | int fd = open("/dev/mem", O_RDWR); 190 | if (fd < 1) { 191 | handleError("Can't open /dev/mem"); 192 | } 193 | 194 | //this->pageSize=sysconf(_SC_PAGESIZE); 195 | 196 | // calculate the number of pages required for the memory-map address space 197 | unsigned numPages = (MEM_INT_ADDR_SPACE * (MMAP_DATA_WIDTH/8)) / PAGE_SIZE; 198 | mmapPages = new unsigned*[numPages]; 199 | 200 | // save a ptr to the start of each page. 201 | // This is necessary because the pages are unlikely to be adjacent 202 | // in physical memory. 203 | for (unsigned i=0; i < numPages; i++) { 204 | 205 | unsigned startAddr = AXI_MMAP_ADDR+i*PAGE_SIZE; 206 | unsigned pageAddr = (startAddr & (~(PAGE_SIZE-1))); 207 | unsigned pageOffset = startAddr - pageAddr; 208 | 209 | void *ptr = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, pageAddr); 210 | mmapPages[i] = (unsigned *) ptr + pageOffset; 211 | } 212 | } 213 | 214 | 215 | inline void Board::handleError(std::string str) const { 216 | std::cerr << str << std::endl; 217 | throw 1; 218 | } 219 | 220 | 221 | inline bool Board::write(unsigned *data, unsigned long addr, unsigned long words) { 222 | 223 | // identify the starting page, the number of pages for the 224 | // entire transfer, and the addr within the starting page 225 | unsigned page = addr*sizeof(unsigned) / PAGE_SIZE; 226 | unsigned pages = ceil(words*sizeof(unsigned) / (float) PAGE_SIZE); 227 | addr = addr % (PAGE_SIZE/4); 228 | 229 | // for each page, transfer the corresponding data 230 | for (unsigned i=0; i < pages; i++) { 231 | 232 | unsigned pageWords = words > PAGE_SIZE/4 ? PAGE_SIZE/4 - addr : words; 233 | memcpy(mmapPages[page]+addr, data+i*PAGE_SIZE/4, pageWords*sizeof(unsigned)); 234 | addr = 0; 235 | words -= pageWords; 236 | page ++; 237 | } 238 | 239 | return true; 240 | } 241 | 242 | 243 | inline bool Board::read(unsigned *data, unsigned long addr, unsigned long words) { 244 | 245 | // identify the starting page, the number of pages for the 246 | // entire transfer, and the addr within the starting page 247 | unsigned page = addr*sizeof(unsigned) / PAGE_SIZE; 248 | unsigned pages = ceil(words*sizeof(unsigned) / (float) PAGE_SIZE); 249 | addr = addr % (PAGE_SIZE/4); 250 | 251 | // for each page, transfer the corresponding data 252 | for (unsigned i=0; i < pages; i++) { 253 | 254 | unsigned pageWords = words > PAGE_SIZE/4 ? PAGE_SIZE/4 - addr : words; 255 | memcpy(data+i*PAGE_SIZE/4, mmapPages[page]+addr, pageWords*sizeof(unsigned)); 256 | addr = 0; 257 | words -= pageWords; 258 | page ++; 259 | } 260 | 261 | return true; 262 | } 263 | -------------------------------------------------------------------------------- /VHDL/datapath.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | entity datapath is 6 | generic ( 7 | WIDTH : positive := 8); 8 | port ( 9 | clk : in std_logic; 10 | rst : in std_logic; 11 | out_prev_row : in std_logic_vector(89 downto 0); 12 | out_curr_row : in std_logic_vector(89 downto 0); 13 | out_next_row : in std_logic_vector(89 downto 0); 14 | gx1 : in std_logic_vector(width-1 downto 0); 15 | gx2 : in std_logic_vector(width-1 downto 0); 16 | gx3 : in std_logic_vector(width-1 downto 0); 17 | gx4 : in std_logic_vector(width-1 downto 0); 18 | gy1 : in std_logic_vector(width-1 downto 0); 19 | gy2 : in std_logic_vector(width-1 downto 0); 20 | gy3 : in std_logic_vector(width-1 downto 0); 21 | gy4 : in std_logic_vector(width-1 downto 0); 22 | vld_in : in std_logic; 23 | vld_out: out std_logic; 24 | mag : out std_logic_vector(59 downto 0); 25 | th_input_prev : out std_logic_vector(89 downto 0); 26 | th_input_curr : out std_logic_vector(89 downto 0); 27 | th_input_next : out std_logic_vector(89 downto 0) 28 | 29 | 30 | ); 31 | end datapath; 32 | 33 | architecture structural of datapath is 34 | 35 | signal reg1_out, reg2_out, reg3_out, reg4_out, reg5_out, reg6_out, reg7_out, reg8_out : std_logic_vector(width-1 downto 0); 36 | 37 | signal a1,a2,a3,a4,b1,b2,b3,b4 : std_logic_vector(width-1 downto 0); 38 | 39 | signal bl1,bl2,bl3,bl4,a31,a32,a33,a34,a21,a22,a23,a24,a11,a12,a13,a14,a1_out1,a2_out1,a3_out1,a4_out1,a1_out2,a2_out2,a3_out2,a4_out2,a1_out3,a2_out3,a3_out3,a4_out3 : std_logic_vector(width-1 downto 0); 40 | 41 | signal add_b_1,add_b_2,add_b_3,add_b_4,add_a_1,add_a_2,add_a_3,add_a_4 : std_logic_vector(width downto 0); 42 | 43 | signal add_1,add_2,add_3,add_4 : std_logic_vector(width+1 downto 0); 44 | 45 | signal vld1, vld2, vld3, vld4, vld5: std_logic; 46 | 47 | 48 | 49 | begin 50 | REG1 : entity work.reg generic map(width) port map(clk, rst, vld_in, gx1, reg1_out); 51 | REG2 : entity work.reg generic map(width) port map(clk, rst, vld_in, gx2, reg2_out); 52 | REG3 : entity work.reg generic map(width) port map(clk, rst, vld_in, gx3, reg3_out); 53 | REG4 : entity work.reg generic map(width) port map(clk, rst, vld_in, gx4, reg4_out); 54 | REG5 : entity work.reg generic map(width) port map(clk, rst, vld_in, gy1, reg5_out); 55 | REG6 : entity work.reg generic map(width) port map(clk, rst, vld_in, gy2, reg6_out); 56 | REG7 : entity work.reg generic map(width) port map(clk, rst, vld_in, gy3, reg7_out); 57 | REG8 : entity work.reg generic map(width) port map(clk, rst, vld_in, gy4, reg8_out); 58 | 59 | REGV1 : entity work.regbit port map(clk, rst, '1', vld_in, vld1); 60 | REGV2 : entity work.regbit port map(clk, rst, '1', vld1, vld2); 61 | REGV3 : entity work.regbit port map(clk, rst, '1', vld2, vld3); 62 | REGV4 : entity work.regbit port map(clk, rst, '1', vld3, vld4); 63 | REGV5 : entity work.regbit port map(clk, rst, '1', vld4, vld5); 64 | REGV6 : entity work.regbit port map(clk, rst, '1', vld5, vld_out); 65 | 66 | -------------------------------------------------------------------------------------------------------------------------- 67 | 68 | U_CMP1 : entity work.comparator generic map (width) port map (clk, rst, vld1, reg1_out, reg5_out, a1, b1); 69 | U_CMP2 : entity work.comparator generic map (width) port map (clk, rst, vld1, reg2_out, reg6_out, a2, b2); 70 | U_CMP3 : entity work.comparator generic map (width) port map (clk, rst, vld1, reg3_out, reg7_out, a3, b3); 71 | U_CMP4 : entity work.comparator generic map (width) port map (clk, rst, vld1, reg4_out, reg8_out, a4, b4); 72 | 73 | --------------------------------------------------------------------------------------------------------------------------- 74 | 75 | U_SHIFT_B1 : entity work.shift1 generic map (width) port map (clk, rst, vld2, b1, bl1); 76 | U_SHIFT_B2 : entity work.shift1 generic map (width) port map (clk, rst, vld2, b2, bl2); 77 | U_SHIFT_B3 : entity work.shift1 generic map (width) port map (clk, rst, vld2, b3, bl3); 78 | U_SHIFT_B4 : entity work.shift1 generic map (width) port map (clk, rst, vld2, b4, bl4); 79 | 80 | U_SHIFT3_1 : entity work.shift3 generic map (width) port map (clk, rst, vld2, a1, a31); 81 | U_SHIFT3_2 : entity work.shift3 generic map (width) port map (clk, rst, vld2, a2, a32); 82 | U_SHIFT3_3 : entity work.shift3 generic map (width) port map (clk, rst, vld2, a3, a33); 83 | U_SHIFT3_4 : entity work.shift3 generic map (width) port map (clk, rst, vld2, a4, a34); 84 | 85 | U_SHIFT2_1 : entity work.shift2 generic map (width) port map (clk, rst, vld2, a1, a21); 86 | U_SHIFT2_2 : entity work.shift2 generic map (width) port map (clk, rst, vld2, a2, a22); 87 | U_SHIFT2_3 : entity work.shift2 generic map (width) port map (clk, rst, vld2, a3, a23); 88 | U_SHIFT2_4 : entity work.shift2 generic map (width) port map (clk, rst, vld2, a4, a24); 89 | 90 | U_SHIFT_1 : entity work.shift1 generic map (width) port map (clk, rst, vld2, a1, a11); 91 | U_SHIFT_2 : entity work.shift1 generic map (width) port map (clk, rst, vld2, a2, a12); 92 | U_SHIFT_3 : entity work.shift1 generic map (width) port map (clk, rst, vld2, a3, a13); 93 | U_SHIFT_4 : entity work.shift1 generic map (width) port map (clk, rst, vld2, a4, a14); 94 | 95 | REG_A1 : entity work.reg generic map(width) port map(clk, rst, vld2, a1, a1_out1); 96 | REG_A2 : entity work.reg generic map(width) port map(clk, rst, vld2, a2, a2_out1); 97 | REG_A3 : entity work.reg generic map(width) port map(clk, rst, vld2, a3, a3_out1); 98 | REG_A4 : entity work.reg generic map(width) port map(clk, rst, vld2, a4, a4_out1); 99 | 100 | --------------------------------------------------------------------------------------------------------------------------------------- 101 | 102 | U_ADD_B1 : entity work.add_pipe generic map (width, width) port map (clk, rst, vld3, bl1, a31, add_b_1); 103 | U_ADD_B2 : entity work.add_pipe generic map (width, width) port map (clk, rst, vld3, bl2, a32, add_b_2); 104 | U_ADD_B3 : entity work.add_pipe generic map (width, width) port map (clk, rst, vld3, bl3, a33, add_b_3); 105 | U_ADD_B4 : entity work.add_pipe generic map (width, width) port map (clk, rst, vld3, bl4, a34, add_b_4); 106 | 107 | U_ADD_A1 : entity work.add_pipe generic map (width, width) port map (clk, rst, vld3, a21, a11, add_a_1); 108 | U_ADD_A2 : entity work.add_pipe generic map (width, width) port map (clk, rst, vld3, a22, a12, add_a_2); 109 | U_ADD_A3 : entity work.add_pipe generic map (width, width) port map (clk, rst, vld3, a23, a13, add_a_3); 110 | U_ADD_A4 : entity work.add_pipe generic map (width, width) port map (clk, rst, vld3, a24, a14, add_a_4); 111 | 112 | REG_A11 : entity work.reg generic map(width) port map(clk, rst, vld3, a1_out1, a1_out2); 113 | REG_A22 : entity work.reg generic map(width) port map(clk, rst, vld3, a2_out1, a2_out2); 114 | REG_A33 : entity work.reg generic map(width) port map(clk, rst, vld3, a3_out1, a3_out2); 115 | REG_A44 : entity work.reg generic map(width) port map(clk, rst, vld3, a4_out1, a4_out2); 116 | 117 | --------------------------------------------------------------------------------------------------------------------------------------------- 118 | 119 | U_ADD1 : entity work.add_pipe generic map (width+1, width+1) port map (clk, rst, vld4, add_b_1, add_a_1, add_1); 120 | U_ADD2 : entity work.add_pipe generic map (width+1, width+1) port map (clk, rst, vld4, add_b_2, add_a_2, add_2); 121 | U_ADD3 : entity work.add_pipe generic map (width+1, width+1) port map (clk, rst, vld4, add_b_3, add_a_3, add_3); 122 | U_ADD4 : entity work.add_pipe generic map (width+1, width+1) port map (clk, rst, vld4, add_b_4, add_a_4, add_4); 123 | 124 | REG_A111 : entity work.reg generic map(width) port map(clk, rst, vld4, a1_out2, a1_out3); 125 | REG_A222 : entity work.reg generic map(width) port map(clk, rst, vld4, a2_out2, a2_out3); 126 | REG_A333 : entity work.reg generic map(width) port map(clk, rst, vld4, a3_out2, a3_out3); 127 | REG_A444 : entity work.reg generic map(width) port map(clk, rst, vld4, a4_out2, a4_out3); 128 | 129 | --------------------------------------------------------------------------------------------------------------------------------------------- 130 | 131 | U_CMP_1 : entity work.comparator1 generic map(width) port map (clk, rst, vld5, add_1, a1_out3, mag(59 downto 45)); 132 | U_CMP_2 : entity work.comparator1 generic map(width) port map (clk, rst, vld5, add_2, a2_out3, mag(44 downto 30)); 133 | U_CMP_3 : entity work.comparator1 generic map(width) port map (clk, rst, vld5, add_3, a3_out3, mag(29 downto 15)); 134 | U_CMP_4 : entity work.comparator1 generic map(width) port map (clk, rst, vld5, add_4, a4_out3, mag(14 downto 0)); 135 | 136 | -- process(vld5) 137 | -- begin 138 | -- if(vld5 = '1' and (clk'event and clk = '1') ) then 139 | th_input_prev <= out_prev_row; 140 | th_input_curr <= out_curr_row; 141 | th_input_next <= out_next_row; 142 | -- end if; 143 | -- end process; 144 | 145 | end structural; 146 | -------------------------------------------------------------------------------- /CPP/main.cpp: -------------------------------------------------------------------------------- 1 | // main.cpp 2 | // Description: This file is the software portion of the 3 | // Canny Edge Detection algorithm implemented on the FPGA 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | #include "Board.h" 15 | #include "Timer.h" 16 | 17 | 18 | using namespace std; 19 | 20 | 21 | // DONOT CHANGE WITHOUT ALSO CHANGING VHDL TO MATCH 22 | #define ADDR_WIDTH 15 23 | #define MAX_SIZE (1<> dataInput[i]; 39 | } 40 | fin.close(); 41 | } 42 | 43 | 44 | // function to convert data to words 45 | void HW_Data_To_Words(unsigned dataInput[128*128], unsigned hwInput[4096]) 46 | { 47 | for (unsigned i=0, j=0; j<128*128; i++, j+=4) 48 | { 49 | // pack 4 8-bit words into one 32-bit words 50 | hwInput[i] = ((dataInput[j]) & 0xff) << 24 | 51 | ((dataInput[j+1]) & 0xff) << 16 | 52 | ((dataInput[j+2]) & 0xff) << 8 | 53 | ((dataInput[j+3]) & 0xff); 54 | } 55 | } 56 | 57 | 58 | // function to convert words to data 59 | void HW_Words_To_Data(unsigned hwOutput[3844], unsigned dataOutput[124*124]) 60 | { 61 | for (unsigned i=0, j=0; i<3844; i++, j+=4) 62 | { 63 | dataOutput[j] = (hwOutput[i] >> 24) & 0xff; 64 | dataOutput[j+1] = (hwOutput[i] >> 16) & 0xff; 65 | dataOutput[j+2] = (hwOutput[i] >> 8) & 0xff; 66 | dataOutput[j+3] = (hwOutput[i]) & 0xff; 67 | } 68 | 69 | ofstream fout; 70 | fout.open("hw_out.txt", ios::out | ios::trunc); 71 | for(unsigned i=0; i<124*124; i++) 72 | { 73 | fout << dataOutput[i]<> swInput[i][j]; 91 | } 92 | } 93 | fin.close(); 94 | } 95 | 96 | 97 | // software based canny edge detection algorithm 98 | void SW_Canny(int swInput[128][128], int filterx[3][3], int filtery[3][3], int th1, int th2, int swOutput[124][124]) 99 | { 100 | int gx[126][126], gy[126][126]; 101 | for(int i=0; i<126; i++) 102 | { 103 | for(int j=0; j<126; j++) 104 | { 105 | gx[i][j] = 0; 106 | for(int k=0; k<3; k++) 107 | { 108 | for(int l=0; l<3; l++) 109 | { 110 | gx[i][j] += swInput[i+k][j+l] * filterx[k][l]; 111 | gy[i][j] += swInput[i+k][j+l] * filtery[k][l]; 112 | } 113 | } 114 | } 115 | } 116 | 117 | float magnitude[126][126]; 118 | for(int i=0; i<126; i++) 119 | { 120 | for(int j=0; j<126; j++) 121 | { 122 | magnitude[i][j] = sqrt(gx[i][j] * gx[i][j] + gy[i][j] * gy[i][j]); 123 | } 124 | } 125 | 126 | for(int i=0; i<124; i++) 127 | { 128 | for(int j=0; j<124; j++) 129 | { 130 | if(magnitude[i+1][j+1] > th1) 131 | { 132 | swOutput[i][j] = 255; 133 | continue; 134 | } 135 | if(magnitude[i+1][j+1] < th2) 136 | { 137 | swOutput[i][j] = 0; 138 | continue; 139 | } 140 | if(swInput[i][j] > th1 || swInput[i][j+1] > th1 || 141 | swInput[i][j+2] > th1 || swInput[i+1][j] > th1 || 142 | swInput[i+1][j+2] > th1 || swInput[i+2][j] > th1 || 143 | swInput[i+2][j+1] > th1 || swInput[i+2][j+2] > th1) 144 | { 145 | swOutput[i][j] = 255; 146 | } 147 | else 148 | { 149 | swOutput[i][j] = 0; 150 | } 151 | } 152 | } 153 | 154 | 155 | // rearranging outputs 156 | int temp[124][124]; 157 | for(int i=0; i<124; i++) 158 | { 159 | for(int j=0; j<124; j++) 160 | { 161 | temp[i][j] = swOutput[i][j]; 162 | } 163 | } 164 | for(int i=0; i<124; i++) 165 | { 166 | for(int j=0; j<124; j++) 167 | { 168 | swOutput[i][j] = temp[j][i]; 169 | } 170 | } 171 | } 172 | 173 | 174 | // function to write software based canny edge detected output to file 175 | void SW_Write_Output_Data(int output[124][124]) 176 | { 177 | ofstream fout; 178 | fout.open("sw_out.txt", ios::out | ios::trunc); 179 | for(int i=0; i<124; i++) 180 | for(int j=0; j<124; j++) 181 | { 182 | fout << output[i][j]< clocks(Board::NUM_FPGA_CLOCKS); 219 | clocks[0] = 100.0; 220 | clocks[1] = 0.0; 221 | clocks[2] = 0.0; 222 | clocks[3] = 0.0; 223 | 224 | // initialize board 225 | Board *board; 226 | try 227 | { 228 | board = new Board(argv[1], clocks); 229 | } 230 | catch(...) 231 | { 232 | cout<<"Could not initialize clock frequencies... Exiting!"<write(hwInput, MEM_IN_ADDR, 4096); 251 | board->write(&size, SIZE_ADDR, 1); 252 | writeTime.stop(); 253 | 254 | // assert go. Note that the memory map automatically sets go back to 1 to 255 | // avoid an additional transfer. 256 | go = 1; 257 | board->write(&go, GO_ADDR, 1); 258 | 259 | // wait for the board to assert done 260 | waitTime.start(); 261 | done = 0; 262 | while (!done) 263 | { 264 | board->read(&done, DONE_ADDR, 1); 265 | } 266 | waitTime.stop(); 267 | 268 | // read the outputs back from the FPGA 269 | readTime.start(); 270 | board->read(hwOutput, MEM_OUT_ADDR, 3844); 271 | readTime.stop(); 272 | hwTime.stop(); 273 | HW_Words_To_Data(hwOutput, dataOutput); 274 | 275 | 276 | /* 277 | * software implementation 278 | */ 279 | int swInput[128][128]; 280 | int filter1[3][3] = {{1,2,1},{0,0,0},{-1,-2,-1}}; 281 | int filter2[3][3] = {{1,0,-1},{2,0,-2},{1,0,-1}}; 282 | int swOutput[124][124]; 283 | int th1=100, th2=30; 284 | Timer swTime; 285 | 286 | SW_Read_Input_Data(swInput); 287 | swTime.start(); 288 | SW_Canny(swInput, filter1, filter2, th1, th2, swOutput); 289 | swTime.stop(); 290 | SW_Write_Output_Data(swOutput); 291 | 292 | 293 | /* 294 | * check if hardware and software outputs match 295 | * -- should not match due to use of approximate methods in hardware implementation 296 | */ 297 | //Check_HW_SW_Output(dataOutput, swOutput); 298 | 299 | 300 | /* 301 | * calculate speedup 302 | */ 303 | double transferTime = writeTime.elapsedTime() + readTime.elapsedTime(); 304 | double hwTimeNoTransfer = hwTime.elapsedTime() - transferTime; 305 | cout << "Speedup: " << swTime.elapsedTime()/hwTime.elapsedTime() << endl; 306 | cout << "Speedup (no transfers): " << swTime.elapsedTime()/hwTimeNoTransfer << endl; 307 | } 308 | -------------------------------------------------------------------------------- /VHDL/gxgyBuffer.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | use work.config_pkg.all; 5 | 6 | entity gxgyBuffer is 7 | generic (width : positive := 64; 8 | inputWidth : positive := 32); 9 | port ( 10 | clk : in std_logic; 11 | rst : in std_logic; 12 | en : in std_logic; 13 | row_count : in std_logic_vector(C_MEM_ADDR_WIDTH downto 0); 14 | input : in std_logic_vector(inputWidth-1 downto 0); 15 | output_prev : out std_logic_vector(inputWidth-1 downto 0); 16 | output_curr : out std_logic_vector(inputWidth-1 downto 0); 17 | output_next : out std_logic_vector(inputWidth-1 downto 0); 18 | vld_out : out std_logic 19 | ); 20 | end gxgyBuffer; 21 | 22 | architecture BHV of gxgyBuffer is 23 | signal state : std_logic_vector(2 downto 0); 24 | signal prev_buffer : std_logic_vector(width-1 downto 0); 25 | signal curr_buffer : std_logic_vector(width-1 downto 0); 26 | signal next_buffer : std_logic_vector(width-1 downto 0); 27 | signal temp_buffer : std_logic_vector((inputWidth/4)-1 downto 0); 28 | signal zero : std_logic_vector((inputWidth/4)-1 downto 0) := (others => '0'); 29 | signal next_buffer_zero : std_logic_vector(width-inputWidth-1 downto 0) := (others => '0'); 30 | 31 | begin 32 | process(clk, rst) 33 | variable ip_count : std_logic_vector(C_MEM_ADDR_WIDTH downto 0) := (others => '0'); 34 | begin 35 | if rst = '1' then 36 | state <= "000"; 37 | prev_buffer <= (others => '0'); 38 | curr_buffer <= (others => '0'); 39 | next_buffer <= (others => '0'); 40 | output_prev <= (others => '0'); 41 | output_curr <= (others => '0'); 42 | output_next <= (others => '0'); 43 | temp_buffer <= (others => '0'); 44 | vld_out <= '0'; 45 | elsif rising_edge(clk) then 46 | if state = "000" then 47 | if en = '1' then 48 | ip_count := std_logic_vector(unsigned(ip_count) + to_unsigned(1, C_MEM_ADDR_WIDTH+1)); 49 | state <= "001"; 50 | if ip_count < row_count then 51 | next_buffer <= next_buffer(width-inputWidth-1 downto 0) & temp_buffer & input(inputWidth-1 downto (inputWidth/4)); 52 | temp_buffer <= input((inputWidth/4)-1 downto 0); 53 | else 54 | next_buffer <= next_buffer(width-inputWidth-1 downto 0) & temp_buffer & input(inputWidth-1 downto (inputWidth/2)) & zero; 55 | temp_buffer <= (others => '0'); 56 | end if; 57 | prev_buffer <= (others => '0'); 58 | curr_buffer <= (others => '0'); 59 | output_prev <= (others => '0'); 60 | output_curr <= (others => '0'); 61 | output_next <= (others => '0'); 62 | vld_out <= '0'; 63 | end if; 64 | elsif state = "001" then 65 | if ip_count < row_count then 66 | ip_count := std_logic_vector(unsigned(ip_count) + to_unsigned(1, C_MEM_ADDR_WIDTH+1)); 67 | state <= "001"; 68 | if ip_count < row_count then 69 | next_buffer <= next_buffer(width-inputWidth-1 downto 0) & temp_buffer & input(inputWidth-1 downto (inputWidth/4)); 70 | temp_buffer <= input((inputWidth/4)-1 downto 0); 71 | else 72 | next_buffer <= next_buffer(width-inputWidth-1 downto 0) & temp_buffer & input(inputWidth-1 downto (inputWidth/2)) & zero; 73 | temp_buffer <= (others => '0'); 74 | end if; 75 | prev_buffer <= (others => '0'); 76 | curr_buffer <= (others => '0'); 77 | output_prev <= (others => '0'); 78 | output_curr <= (others => '0'); 79 | output_next <= (others => '0'); 80 | vld_out <= '0'; 81 | else 82 | ip_count := (0 => '1', others => '0'); 83 | --temp_buffer <= (others => '0'); 84 | state <= "010"; 85 | output_prev <= curr_buffer(width-1 downto width-inputWidth); 86 | output_curr <= next_buffer(width-1 downto width-inputWidth); 87 | output_next <= zero & input(inputWidth-1 downto (inputWidth/4)); 88 | prev_buffer <= curr_buffer; 89 | curr_buffer <= next_buffer; 90 | next_buffer <= next_buffer_zero & zero & input(inputWidth-1 downto (inputWidth/4)); 91 | temp_buffer <= input((inputWidth/4)-1 downto 0); 92 | vld_out <= '1'; 93 | end if; 94 | elsif state = "010" then 95 | if en = '0' then 96 | ip_count := (0 => '1', others => '0'); 97 | state <= "100"; 98 | output_prev <= curr_buffer(width-1 downto width-inputWidth); 99 | output_curr <= next_buffer(width-1 downto width-inputWidth); 100 | output_next <= (others => '0'); 101 | temp_buffer <= (others => '0'); 102 | prev_buffer <= curr_buffer; 103 | curr_buffer <= next_buffer; 104 | next_buffer <= (others => '0'); 105 | vld_out <= '1'; 106 | else 107 | if ip_count < row_count then 108 | ip_count := std_logic_vector(unsigned(ip_count) + to_unsigned(1, C_MEM_ADDR_WIDTH+1)); 109 | state <= "011"; 110 | output_prev <= prev_buffer(width-1-(inputWidth*(to_integer(unsigned(ip_count))-1)) downto width-(inputWidth*to_integer(unsigned(ip_count)))); 111 | output_curr <= curr_buffer(width-1-(inputWidth*(to_integer(unsigned(ip_count))-1)) downto width-(inputWidth*to_integer(unsigned(ip_count)))); 112 | prev_buffer <= prev_buffer; 113 | curr_buffer <= curr_buffer; 114 | if ip_count < row_count then 115 | output_next <= temp_buffer & input(inputWidth-1 downto (inputWidth/4)); 116 | next_buffer <= next_buffer(width-inputWidth-1 downto 0) & temp_buffer & input(inputWidth-1 downto (inputWidth/4)); 117 | temp_buffer <= input((inputWidth/4)-1 downto 0); 118 | else 119 | output_next <= temp_buffer & input(inputWidth-1 downto (inputWidth/2)) & zero; 120 | next_buffer <= next_buffer(width-inputWidth-1 downto 0) & temp_buffer & input(inputWidth-1 downto (inputWidth/2)) & zero; 121 | temp_buffer <= (others => '0'); 122 | end if; 123 | vld_out <= '1'; 124 | else 125 | ip_count := (0 => '1', others => '0'); 126 | state <= "010"; 127 | output_prev <= curr_buffer(width-1 downto width-inputWidth); 128 | output_curr <= next_buffer(width-1 downto width-inputWidth); 129 | output_next <= zero & input(inputWidth-1 downto (inputWidth/4)); 130 | prev_buffer <= curr_buffer; 131 | curr_buffer <= next_buffer; 132 | next_buffer <= next_buffer_zero & zero & input(inputWidth-1 downto (inputWidth/4)); 133 | temp_buffer <= input((inputWidth/4)-1 downto 0); 134 | vld_out <= '1'; 135 | end if; 136 | end if; 137 | elsif state = "011" then 138 | if en = '0' then 139 | ip_count := (0 => '1', others => '0'); 140 | state <= "100"; 141 | output_prev <= curr_buffer(width-1 downto width-inputWidth); 142 | output_curr <= next_buffer(width-1 downto width-inputWidth); 143 | output_next <= (others => '0'); 144 | temp_buffer <= (others => '0'); 145 | prev_buffer <= curr_buffer; 146 | curr_buffer <= next_buffer; 147 | next_buffer <= (others => '0'); 148 | vld_out <= '1'; 149 | else 150 | if ip_count < row_count then 151 | ip_count := std_logic_vector(unsigned(ip_count) + to_unsigned(1, C_MEM_ADDR_WIDTH+1)); 152 | state <= "011"; 153 | output_prev <= prev_buffer(width-1-(inputWidth*(to_integer(unsigned(ip_count))-1)) downto width-(inputWidth*to_integer(unsigned(ip_count)))); 154 | output_curr <= curr_buffer(width-1-(inputWidth*(to_integer(unsigned(ip_count))-1)) downto width-(inputWidth*to_integer(unsigned(ip_count)))); 155 | prev_buffer <= prev_buffer; 156 | curr_buffer <= curr_buffer; 157 | if ip_count < row_count then 158 | output_next <= temp_buffer & input(inputWidth-1 downto (inputWidth/4)); 159 | next_buffer <= next_buffer(width-inputWidth-1 downto 0) & temp_buffer & input(inputWidth-1 downto (inputWidth/4)); 160 | temp_buffer <= input((inputWidth/4)-1 downto 0); 161 | else 162 | output_next <= temp_buffer & input(inputWidth-1 downto (inputWidth/2)) & zero; 163 | next_buffer <= next_buffer(width-inputWidth-1 downto 0) & temp_buffer & input(inputWidth-1 downto (inputWidth/2)) & zero; 164 | temp_buffer <= (others => '0'); 165 | end if; 166 | vld_out <= '1'; 167 | else 168 | ip_count := (0 => '1', others => '0'); 169 | --temp_buffer <= (others => '0'); 170 | state <= "010"; 171 | output_prev <= curr_buffer(width-1 downto width-inputWidth); 172 | output_curr <= next_buffer(width-1 downto width-inputWidth); 173 | output_next <= zero & input(inputWidth-1 downto (inputWidth/4)); 174 | prev_buffer <= curr_buffer; 175 | curr_buffer <= next_buffer; 176 | next_buffer <= next_buffer_zero & zero & input(inputWidth-1 downto (inputWidth/4)); 177 | temp_buffer <= input((inputWidth/4)-1 downto 0); 178 | vld_out <= '1'; 179 | end if; 180 | end if; 181 | elsif state = "100" then 182 | if ip_count < row_count then 183 | ip_count := std_logic_vector(unsigned(ip_count) + to_unsigned(1, C_MEM_ADDR_WIDTH+1)); 184 | state <= "101"; 185 | output_prev <= prev_buffer(width-1-(inputWidth*(to_integer(unsigned(ip_count))-1)) downto width-(inputWidth*to_integer(unsigned(ip_count)))); 186 | output_curr <= curr_buffer(width-1-(inputWidth*(to_integer(unsigned(ip_count))-1)) downto width-(inputWidth*to_integer(unsigned(ip_count)))); 187 | output_next <= (others => '0'); 188 | temp_buffer <= (others => '0'); 189 | prev_buffer <= prev_buffer; 190 | curr_buffer <= curr_buffer; 191 | next_buffer <= (others => '0'); 192 | vld_out <= '1'; 193 | else 194 | ip_count := (others => '0'); 195 | state <= "000"; 196 | prev_buffer <= (others => '0'); 197 | curr_buffer <= (others => '0'); 198 | next_buffer <= (others => '0'); 199 | output_prev <= (others => '0'); 200 | output_curr <= (others => '0'); 201 | output_next <= (others => '0'); 202 | temp_buffer <= (others => '0'); 203 | vld_out <= '0'; 204 | end if; 205 | elsif state = "101" then 206 | if ip_count < row_count then 207 | ip_count := std_logic_vector(unsigned(ip_count) + to_unsigned(1, C_MEM_ADDR_WIDTH+1)); 208 | state <= "101"; 209 | output_prev <= prev_buffer(width-1-(inputWidth*(to_integer(unsigned(ip_count))-1)) downto width-(inputWidth*to_integer(unsigned(ip_count)))); 210 | output_curr <= curr_buffer(width-1-(inputWidth*(to_integer(unsigned(ip_count))-1)) downto width-(inputWidth*to_integer(unsigned(ip_count)))); 211 | output_next <= (others => '0'); 212 | temp_buffer <= (others => '0'); 213 | prev_buffer <= prev_buffer; 214 | curr_buffer <= curr_buffer; 215 | next_buffer <= (others => '0'); 216 | vld_out <= '1'; 217 | else 218 | ip_count := (others => '0'); 219 | state <= "000"; 220 | prev_buffer <= (others => '0'); 221 | curr_buffer <= (others => '0'); 222 | next_buffer <= (others => '0'); 223 | output_prev <= (others => '0'); 224 | output_curr <= (others => '0'); 225 | output_next <= (others => '0'); 226 | temp_buffer <= (others => '0'); 227 | vld_out <= '0'; 228 | end if; 229 | end if; 230 | end if; 231 | end process; 232 | end BHV; 233 | -------------------------------------------------------------------------------- /VHDL/user_app.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | use work.config_pkg.all; 6 | --use work.user_pkg.all; 7 | 8 | entity user_app is 9 | port ( 10 | clk : in std_logic; 11 | rst : in std_logic; 12 | 13 | -- memory-map interface 14 | mmap_wr_en : in std_logic; 15 | mmap_wr_addr : in std_logic_vector(MMAP_ADDR_RANGE); 16 | mmap_wr_data : in std_logic_vector(MMAP_DATA_RANGE); 17 | mmap_rd_en : in std_logic; 18 | mmap_rd_addr : in std_logic_vector(MMAP_ADDR_RANGE); 19 | mmap_rd_data : out std_logic_vector(MMAP_DATA_RANGE) 20 | ); 21 | end user_app; 22 | 23 | architecture default of user_app is 24 | 25 | signal go : std_logic; 26 | signal size : std_logic_vector(C_MEM_ADDR_WIDTH downto 0); 27 | signal done : std_logic; 28 | 29 | signal mem_in_wr_data : std_logic_vector(C_MEM_IN_WIDTH-1 downto 0); 30 | signal mem_in_wr_addr : std_logic_vector(C_MEM_ADDR_WIDTH-1 downto 0); 31 | signal mem_in_rd_data1 : std_logic_vector(C_MEM_IN_WIDTH-1 downto 0); 32 | signal mem_in_rd_addr1 : std_logic_vector(C_MEM_ADDR_WIDTH-1 downto 0) := (others => '0'); 33 | signal mem_in_rd_data2 : std_logic_vector(C_MEM_IN_WIDTH-1 downto 0); 34 | signal mem_in_rd_addr2 : std_logic_vector(C_MEM_ADDR_WIDTH-1 downto 0) := (others => '0'); 35 | signal mem_in_rd_data3 : std_logic_vector(C_MEM_IN_WIDTH-1 downto 0); 36 | signal mem_in_rd_addr3 : std_logic_vector(C_MEM_ADDR_WIDTH-1 downto 0) := (others => '0'); 37 | signal mem_in_wr_en : std_logic; 38 | signal mem_in_rd_addr_valid : std_logic; 39 | 40 | signal data_vld : std_logic; 41 | signal data_vld_addr_gen : std_logic; 42 | signal smartBuff_en : std_logic; 43 | signal datapath_valid_in : std_logic; 44 | 45 | signal row_count : std_logic_vector(C_MEM_ADDR_WIDTH downto 0) := std_logic_vector(to_unsigned(C_COLUMN_COUNT, C_MEM_ADDR_WIDTH+1)); 46 | 47 | signal gx_result : std_logic_vector(51 downto 0); 48 | signal gy_result : std_logic_vector(51 downto 0); 49 | signal mag_en : std_logic_vector(3 downto 0); 50 | signal buffer_en : std_logic; 51 | signal mag_result : std_logic_vector(59 downto 0); 52 | 53 | 54 | signal input_prev : std_logic_vector(47 downto 0); 55 | signal input_curr : std_logic_vector(47 downto 0); 56 | signal input_next : std_logic_vector(47 downto 0); 57 | 58 | signal mag_prev : std_logic_vector(59 downto 0); 59 | signal mag_curr : std_logic_vector(59 downto 0); 60 | signal mag_next : std_logic_vector(59 downto 0); 61 | signal mag_valid : std_logic; 62 | 63 | signal th_input_prev : std_logic_vector(89 downto 0); 64 | signal th_input_curr : std_logic_vector(89 downto 0); 65 | signal th_input_next : std_logic_vector(89 downto 0); 66 | signal th_valid : std_logic; 67 | 68 | signal rslt_rdy : std_logic; 69 | 70 | 71 | signal mem_out_wr_data : std_logic_vector(C_MEM_OUT_WIDTH-1 downto 0) := (others => '0'); 72 | signal mem_out_wr_addr : std_logic_vector(C_MEM_ADDR_WIDTH-1 downto 0) := (others => '0'); 73 | signal mem_out_rd_data : std_logic_vector(C_MEM_OUT_WIDTH-1 downto 0); 74 | signal mem_out_rd_addr : std_logic_vector(C_MEM_ADDR_WIDTH-1 downto 0); 75 | signal mem_out_wr_en : std_logic_vector(3 downto 0); 76 | signal mem_out_wr_data_valid : std_logic; 77 | signal mem_out_done : std_logic; 78 | 79 | signal out_prev_row : std_logic_vector(89 downto 0); 80 | signal out_curr_row : std_logic_vector(89 downto 0); 81 | signal out_next_row : std_logic_vector(89 downto 0); 82 | signal prev_row : std_logic_vector(89 downto 0); 83 | signal curr_row : std_logic_vector(89 downto 0); 84 | signal next_row : std_logic_vector(89 downto 0); 85 | 86 | begin 87 | 88 | 89 | ------------------------------------------------------------------------------ 90 | U_MMAP : entity work.memory_map 91 | port map ( 92 | clk => clk, 93 | rst => rst, 94 | wr_en => mmap_wr_en, 95 | wr_addr => mmap_wr_addr, 96 | wr_data => mmap_wr_data, 97 | rd_en => mmap_rd_en, 98 | rd_addr => mmap_rd_addr, 99 | rd_data => mmap_rd_data, 100 | 101 | -- TODO: connect to appropriate logic 102 | go => go, 103 | size => size, 104 | done => done, 105 | 106 | -- already connected to block RAMs 107 | -- the memory map functionality writes to the input ram 108 | -- and reads from the output ram 109 | mem_in_wr_data => mem_in_wr_data, 110 | mem_in_wr_addr => mem_in_wr_addr, 111 | mem_in_wr_en => mem_in_wr_en, 112 | mem_out_rd_data => mem_out_rd_data, 113 | mem_out_rd_addr => mem_out_rd_addr 114 | ); 115 | ------------------------------------------------------------------------------ 116 | 117 | 118 | ------------------------------------------------------------------------------ 119 | -- input memory 120 | -- written to by memory map 121 | -- read from by controller+datapath 122 | U_MEM_IN : entity work.ip_ram(SYNC_READ) 123 | generic map ( 124 | num_words => 2**C_MEM_ADDR_WIDTH, 125 | word_width => C_MEM_IN_WIDTH, 126 | addr_width => C_MEM_ADDR_WIDTH) 127 | port map ( 128 | clk => clk, 129 | wen => mem_in_wr_en, 130 | waddr => mem_in_wr_addr, 131 | wdata => mem_in_wr_data, 132 | raddr1 => mem_in_rd_addr1, -- TODO: connect to input address generator prev row 133 | rdata1 => mem_in_rd_data1, -- TODO: connect to smart buffer 1 134 | raddr2 => mem_in_rd_addr2, -- TODO: connect to input address generator current row 135 | rdata2 => mem_in_rd_data2, -- TODO: connect to smart buffer 2 136 | raddr3 => mem_in_rd_addr3, -- TODO: connect to input address generator next row 137 | rdata3 => mem_in_rd_data3); -- TODO: connect to smart buffer 3 138 | ------------------------------------------------------------------------------ 139 | 140 | 141 | ------------------------------------------------------------------------------ 142 | -- output memory 143 | -- written to by controller+datapath 144 | -- read from by memory map 145 | U_MEM_OUT : entity work.op_ram(SYNC_READ) 146 | generic map ( 147 | num_words => 2**C_MEM_ADDR_WIDTH, 148 | word_width => C_MEM_OUT_WIDTH, 149 | addr_width => C_MEM_ADDR_WIDTH) 150 | port map ( 151 | clk => clk, 152 | wen => mem_out_wr_en(0), --cs_datapath_vld(0), --gx_valid, --gxBuffer_en(0), --mem_out_wr_en(0), 153 | waddr => mem_out_wr_addr, -- TODO: connect to output address generator 154 | wdata => mem_out_wr_data, --temp, --cs_result(7 downto 0), --mem_out_wr_data, -- TODO: connect to pipeline output 155 | raddr => mem_out_rd_addr, 156 | rdata => mem_out_rd_data); 157 | ------------------------------------------------------------------------------ 158 | U_CONTROLLER : entity work.controller 159 | port map ( 160 | clk => clk, 161 | rst => rst, 162 | go => go, 163 | rslt_rdy => rslt_rdy, 164 | done => done, 165 | data_vld => data_vld 166 | ); 167 | ------------------------------------------------------------------------------ 168 | U_IP_ADD_GEN_PREV_ROW : entity work.ip_address_generator_prow 169 | port map ( 170 | clk => clk, 171 | rst => rst, 172 | en => data_vld, 173 | --size => size, 174 | add_out => mem_in_rd_addr1 175 | ); 176 | ------------------------------------------------------------------------------ 177 | U_PREV_ROW_SMART_BUFFER : entity work.smart_buff 178 | generic map ( 179 | width => 32, 180 | outputWidth => 48) 181 | port map ( 182 | clk => clk, 183 | rst => rst, 184 | en => smartBuff_en, 185 | input => mem_in_rd_data1, 186 | output => input_prev 187 | ); 188 | ------------------------------------------------------------------------------ 189 | U_IP_ADD_GEN_CURR_ROW : entity work.ip_address_generator_crow 190 | port map ( 191 | clk => clk, 192 | rst => rst, 193 | en => data_vld, 194 | --size => size, 195 | add_out => mem_in_rd_addr2, 196 | vld_out => data_vld_addr_gen 197 | ); 198 | ------------------------------------------------------------------------------ 199 | U_REG_VLD_ADDR_GEN : entity work.regbit port map(clk, rst, '1', data_vld_addr_gen, smartBuff_en); 200 | ------------------------------------------------------------------------------ 201 | U_CURR_ROW_SMART_BUFFER : entity work.smart_buff_v 202 | generic map ( 203 | width => 32, 204 | outputWidth => 48) 205 | port map ( 206 | clk => clk, 207 | rst => rst, 208 | en => smartBuff_en, 209 | input => mem_in_rd_data2, 210 | valid => datapath_valid_in, 211 | output => input_curr 212 | ); 213 | ------------------------------------------------------------------------------ 214 | U_IP_ADD_GEN_NEXT_ROW : entity work.ip_address_generator_nrow 215 | port map ( 216 | clk => clk, 217 | rst => rst, 218 | en => data_vld, 219 | --size => size, 220 | add_out => mem_in_rd_addr3 221 | ); 222 | ------------------------------------------------------------------------------ 223 | U_NEXT_ROW_SMART_BUFFER : entity work.smart_buff 224 | generic map ( 225 | width => 32, 226 | outputWidth => 48) 227 | port map ( 228 | clk => clk, 229 | rst => rst, 230 | en => smartBuff_en, 231 | input => mem_in_rd_data3, 232 | output => input_next 233 | ); 234 | ------------------------------------------------------------------------------ 235 | LOOP_UNROLL1: for n in 3 downto 0 generate 236 | DATAPATH_GX : entity work.datapathGx 237 | generic map (8) 238 | port map ( 239 | clk => clk, 240 | rst => rst, 241 | prev_row => input_prev, 242 | curr_row => input_curr, 243 | next_row => input_next, 244 | input_prev => input_prev(8*(n+3)-1 downto 8*n), --mem_in_rd_data1(23 downto 0), 245 | input_curr => input_curr(8*(n+3)-1 downto 8*n), --mem_in_rd_data2(23 downto 0), 246 | input_next => input_next(8*(n+3)-1 downto 8*n), --mem_in_rd_data3(23 downto 0), 247 | sob_coeff1 => "01", 248 | sob_coeff2 => "10", 249 | result => gx_result(13*(n+1)-1 downto 13*n), --mem_out_wr_data(8*(n+1)-1 downto 8*n), 250 | vld_in => datapath_valid_in, --data_vld_addr_gen, 251 | vld_out => mag_en(n), 252 | out_prev_row => out_prev_row, 253 | out_curr_row => out_curr_row, 254 | out_next_row => out_next_row 255 | ); 256 | end generate LOOP_UNROLL1; 257 | ------------------------------------------------------------------------------ 258 | LOOP_UNROLL2: for n in 3 downto 0 generate 259 | DATAPATH_GY : entity work.datapath_gy 260 | generic map (8) 261 | port map ( 262 | clk => clk, 263 | rst => rst, 264 | input_prev => input_prev(8*(n+3)-1 downto 8*n), 265 | input_next => input_next(8*(n+3)-1 downto 8*n), 266 | sob_coeff1 => "01", 267 | sob_coeff2 => "10", 268 | result => gy_result(13*(n+1)-1 downto 13*n), --mem_out_wr_data(8*(n+1)-1 downto 8*n), 269 | vld_in => datapath_valid_in, 270 | vld_out => open 271 | ); 272 | end generate LOOP_UNROLL2; 273 | 274 | U_MAG : entity work.datapath 275 | generic map(width => 13) 276 | port map( 277 | clk => clk, 278 | rst => rst, 279 | out_prev_row => out_prev_row, 280 | out_curr_row => out_curr_row, 281 | out_next_row => out_next_row, 282 | gx1 => gx_result(51 downto 39), 283 | gx2 => gx_result(38 downto 26), 284 | gx3 => gx_result(25 downto 13), 285 | gx4 => gx_result(12 downto 0), 286 | gy1 => gy_result(51 downto 39), 287 | gy2 => gy_result(38 downto 26), 288 | gy3 => gy_result(25 downto 13), 289 | gy4 => gy_result(12 downto 0), 290 | vld_in => mag_en(0), 291 | vld_out => buffer_en, 292 | mag => mag_result, 293 | th_input_prev => th_input_prev, 294 | th_input_curr => th_input_curr, 295 | th_input_next => th_input_next 296 | ); 297 | 298 | -- U_MAG_BUFFER : entity work.gxgyBuffer 299 | -- generic map (width => 60*C_COLUMN_COUNT, inputWidth => 60) 300 | -- port map ( 301 | -- clk => clk, 302 | -- rst => rst, 303 | -- en => buffer_en, 304 | -- row_count => row_count, 305 | -- input => mag_result, 306 | -- output_prev => mag_prev, 307 | -- output_curr => mag_curr, 308 | -- output_next => mag_next, 309 | -- vld_out => mag_valid 310 | -- ); 311 | 312 | -- ------------------------------------------------------------------------------ 313 | -- U_GX_PREV_ROW_SMART_BUFFER : entity work.smart_buff 314 | -- generic map ( 315 | -- width => 60, 316 | -- outputWidth => 90) 317 | -- port map ( 318 | -- clk => clk, 319 | -- rst => rst, 320 | -- en => mag_valid, 321 | -- input => mag_prev, 322 | -- output => th_input_prev 323 | -- ); 324 | -- ------------------------------------------------------------------------------ 325 | -- U_GX_CURR_ROW_SMART_BUFFER : entity work.smart_buff_v 326 | -- generic map ( 327 | -- width => 60, 328 | -- outputWidth => 90) 329 | -- port map ( 330 | -- clk => clk, 331 | -- rst => rst, 332 | -- en => mag_valid, 333 | -- input => mag_curr, 334 | -- valid => th_valid, 335 | -- output => th_input_curr 336 | -- ); 337 | -- ------------------------------------------------------------------------------ 338 | -- U_GX_NEXT_ROW_SMART_BUFFER : entity work.smart_buff 339 | -- generic map ( 340 | -- width => 60, 341 | -- outputWidth => 90) 342 | -- port map ( 343 | -- clk => clk, 344 | -- rst => rst, 345 | -- en => mag_valid, 346 | -- input => mag_next, 347 | -- output => th_input_next 348 | -- ); 349 | -- ------------------------------------------------------------------------------ 350 | 351 | 352 | LOOP_UNROLL_THRESH: for n in 3 downto 0 generate 353 | THRESHOLD_COMPARATOR : entity work.datapath_threshold 354 | generic map (15) 355 | port map( 356 | clk => clk, 357 | rst => rst, 358 | mag => mag_result(15*(n+1) - 1 downto 15*n), 359 | input_prev => th_input_prev(15*(n+3)-1 downto 15*n), 360 | input_curr => th_input_curr(15*(n+3)-1 downto 15*n), 361 | input_next => th_input_next(15*(n+3)-1 downto 15*n), 362 | vld_in => buffer_en, 363 | vld_out => mem_out_wr_en(n), 364 | result => mem_out_wr_data(8*(n+1)-1 downto 8*n) 365 | ); 366 | end generate LOOP_UNROLL_THRESH; 367 | 368 | 369 | 370 | ------------------------------------------------------------------------------ 371 | U_OP_ADD_GEN : entity work.op_address_generator 372 | port map ( 373 | clk => clk, 374 | rst => rst, 375 | en => mem_out_wr_en(0), 376 | add_out => mem_out_wr_addr, 377 | endstream => rslt_rdy 378 | ); 379 | 380 | end default; 381 | --------------------------------------------------------------------------------