------------------------------------------------- -- adder.vhd -- -- Authors: John Koob & Raymond Sung -- Date: Oct 10, 2000 -- Course: EE552 -- Desc: -- -- Pipelined XOR Tree of Combinational Logic -- -- This is an pipelined XOR tree that instantiates -- pipeline registers with combinational XOR blocks -- in between each stage. The combination blocks -- are staggered so that none have common bits. -- -- No handshaking between stages is included. -- -- -- -- R R R R -- e -- XORs --- e --- XORs --- e --- ... --- XORs --- e -- g g g g -- -- -- -- -- If you understand everything here, you are doing well. -- If you have questions, post 'em to the newsgroup. -- -- To assist your understanding, this code has been -- extensively commented. This is a rare event, for sure. -- -- References: 2D array vector idea - J. Gunthorpe, D. O'Reilly -- library ieee; use ieee.std_logic_1164.all; package adder_pkg is constant data_width : positive := 32; constant stages : positive := 4; -- a block of combinational logic component xor_tree is generic (tree_width : positive := 8); port (a_vec, b_vec : in std_logic_vector(tree_width - 1 downto 0); x_vec, y_vec : out std_logic_vector(tree_width - 1 downto 0) ); end component xor_tree; -- the multi-purpose LFSR component component LFSR_GENERIC is generic(Width: positive := 4); -- length of pseudo-random sequence port ( clock: in std_logic; resetn: in std_logic; -- active low reset load: in std_logic; -- active high load enable : in std_logic; -- active high enable parallel_in: in std_logic_vector(Width-1 downto 0); -- seed input parallel_out: out std_logic_vector(Width-1 downto 0); -- output serial_out: out std_logic -- serial out (last shift register) ); end component LFSR_GENERIC; end package adder_pkg; library ieee; use ieee.std_logic_1164.all; library work; use work.adder_pkg.all; entity adder is port (ain, bin : in std_logic_vector(data_width - 1 downto 0); clock, resetn, datain_valid, dataout_request : in std_logic; dataout_valid : buffer std_logic; datain_request : out std_logic; sum: out std_logic_vector(data_width - 1 downto 0) ); end entity adder; architecture RTL of adder is -- the size of a stage after block is divided by pipelines. With -- one stage, stage_width = data_width. constant stage_width : positive := data_width / stages; -- internal signal - inputs to the PRPG, sig. compactor, or pipeline registers signal reg_in_x : std_logic_vector(data_width*(stages+1)-1 downto 0); signal reg_in_y : std_logic_vector(data_width*(stages+1)-1 downto 0); -- internal signal - output from the PRPG, sig. compactor, or pipeline registers signal reg_out_x : std_logic_vector(data_width*(stages+1)-1 downto 0); signal reg_out_y : std_logic_vector(data_width*(stages+1)-1 downto 0); -- control to load LFSR register with parallel data. If held high, LFSR -- acts as an ordinary pipeline register signal load_ctrl : std_logic_vector(stages downto 0); -- enable signal useful for handshaking (no handshaking in here, BTW) signal enable : std_logic_vector(stages downto 0); -- serial output from LFSRs. Not very important here... signal ser_out_x : std_logic_vector(stages downto 0); signal ser_out_y : std_logic_vector(stages downto 0); -- non-visible auxiliary output signal yout : std_logic_vector(data_width - 1 downto 0); begin -- massive generate loop -- Each pass generates a PRPG|pipeline|compactor register plus -- blocks of combinational logic that follow each stage. main_gen : for i in 0 to stages generate -- Here is one way to implement a 2D array in VHDL -- The pipe start and pipe end refer to the start and end -- of each "row" of the array. The width of a row (a "pipe") is -- equivalent to the data_width. constant pipe_start : positive := i*data_width; constant pipe_end : positive := (i+1)*data_width; -- must minus 1 when use -- The block start and block end act as "offsets" into the "row". -- They define a block within each row that corresponds to the -- position of the block of logic in the current stage of the -- pipeline constant block_start : positive := i*stage_width; constant block_end : positive := (i+1)*stage_width; begin -- the PRPG|register|compactor (which one depends on load_ctrl) -- this passes 'a' inputs through to internal signals with prefix 'x' reg_a : component LFSR_GENERIC generic map (Width => data_width) port map (clock => clock, resetn => resetn, load => load_ctrl(i), enable => enable(i), parallel_in => reg_in_x(pipe_end - 1 downto pipe_start), parallel_out => reg_out_x(pipe_end - 1 downto pipe_start), serial_out => ser_out_x(i) ); -- the PRPG|register|compactor (which one depends on load_ctrl) -- this passes 'b' inputs through to internal signals with prefix 'y' reg_b : component LFSR_GENERIC generic map (Width => data_width) port map (clock => clock, resetn => resetn, load => load_ctrl(i), enable => enable(i), parallel_in => reg_in_y(pipe_end - 1 downto pipe_start), parallel_out => reg_out_y(pipe_end - 1 downto pipe_start), serial_out => ser_out_y(i) ); -- instantiate XOR blocks of size 'stage_width' xor_blocks : if (i /= stages) generate begin xor_block : component xor_tree generic map (tree_width => stage_width) port map (a_vec => reg_out_x(pipe_start + block_end - 1 downto pipe_start + block_start), b_vec => reg_out_y(pipe_start + block_end - 1 downto pipe_start + block_start), x_vec => reg_in_x(pipe_end + block_end - 1 downto pipe_end + block_start), y_vec => reg_in_y(pipe_end + block_end - 1 downto pipe_end + block_start) ); -- make connections between blocks and registers at the LSB -- side of the XOR block wires : if (block_start /= 0) generate begin reg_in_x(pipe_end + block_start - 1 downto pipe_end) <= reg_out_x(pipe_start + block_start - 1 downto pipe_start); reg_in_y(pipe_end + block_start - 1 downto pipe_end) <= reg_out_y(pipe_start + block_start - 1 downto pipe_start); end generate wires; -- make connections between blocks and registers at the MSB -- side of the XOR block more_wires : if (block_end /= data_width) generate begin reg_in_x(pipe_end + data_width - 1 downto pipe_end + block_end) <= reg_out_x(pipe_start + data_width - 1 downto pipe_start + block_end); reg_in_y(pipe_end + data_width - 1 downto pipe_end + block_end) <= reg_out_y(pipe_start + data_width - 1 downto pipe_start + block_end); end generate more_wires; end generate xor_blocks; end generate main_gen; -- connect module inputs reg_in_x(data_width-1 downto 0) <= ain; reg_in_y(data_width-1 downto 0) <= bin; -- all LFSRs behave as ordinary registers load_gen : for j in 0 to stages generate begin load_ctrl(j) <= '1'; end generate load_gen; -- Note: if we needed to instantiate a PRPG and a Signature -- compactor inside this architecture, we would only need the -- following two lines of VHDL: :-] -- -- load_prpg is used to parallel load data in the LFSR register -- load_ctrl(0) <= load_prpg; -- load_compact is used to parallel load data in the sig. compactor -- load_ctrl(stages) <= load_compact; -- all registers enabled enable <= (others => '1'); -- connect module outputs (it's easier than ya think) sum <= reg_out_x((stages+1) * data_width-1 downto stages * data_width); yout <= reg_out_y((stages+1) * data_width-1 downto stages * data_width); -- sorry, no handshaking provided dataout_valid <= datain_valid; datain_request <= dataout_request; end RTL;