------------------------------------------------------------------------------- -- Title : Merger for tracks from different z channels -- Project : Prototype implementation of the GTU of the Alice TRD Experiment ------------------------------------------------------------------------------- -- File : zch_merger.vhd -- Author : Jan de Cuveland -- Company : -- Last update: 2004-05-17 -- Platform : ------------------------------------------------------------------------------- -- This is a prototype implementation of the Global Tracking Unit (GTU) -- of the Alice TRD detector. ------------------------------------------------------------------------------- -- Description: ------------------------------------------------------------------------------- -- Revisions : -- Date Version Author Description -- 2003/06/16 1.0 cuveland Created ------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use work.gtu_types.all; use work.track_types.all; ------------------------------------------------------------------------------- entity downgrade is port ( clk : in std_logic; rst_n : in std_logic; pretrigger : in std_logic; valid_in : in std_logic_vector(2 downto 0); ready_in : in std_logic_vector(2 downto 0); track2_in : in std_logic_vector(track_with_idx_width-1 downto 0); track1_in : in std_logic_vector(track_with_idx_width-1 downto 0); track0_in : in std_logic_vector(track_with_idx_width-1 downto 0); valid_out : out std_logic; ready_out : out std_logic; track_out : out std_logic_vector(track_with_zpos_width-1 downto 0)); end; ------------------------------------------------------------------------------- architecture default of downgrade is constant mem_addr_width : integer := 3; -- FIFO depth is 8 words -- input signals type track_with_idx_t3 is array (2 downto 0) of track_with_idx_t; signal track_in : track_with_idx_t3; -- internal signals signal ready_in_reg : std_logic_vector(2 downto 0); type mem_t is array (0 to 2**mem_addr_width-1) of std_logic_vector(track_with_idx_width-1 downto 0); type mem_t3 is array (2 downto 0) of mem_t; signal mem : mem_t3; type track_with_zpos_t3 is array (2 downto 0) of track_with_zpos_t; type idx_t3 is array (2 downto 0) of unsigned(idx_width-1 downto 0); type y_t3 is array (2 downto 0) of signed(approx_ypos_width-1 downto 0); subtype sortnum_t is integer range 0 to 8; type sortnum_t3 is array(2 downto 0) of sortnum_t; signal mem_out : track_with_idx_t3; signal mem_out_with_z : track_with_zpos_t3; signal mem_out_idx : idx_t3; signal mem_out_y : y_t3; signal mem_out_sortnum : sortnum_t3; type mem_addr_t3 is array (2 downto 0) of unsigned(mem_addr_width-1 downto 0); signal wr_addr_reg : mem_addr_t3; signal wr_addr_last : mem_addr_t3; --signal rd_addr_reg : mem_addr_t3; signal next_rd_addr : mem_addr_t3; signal rd_addr_reg_0 : unsigned(mem_addr_width-1 downto 0); signal rd_addr_reg_1 : unsigned(mem_addr_width-1 downto 0); signal rd_addr_reg_2 : unsigned(mem_addr_width-1 downto 0); signal not_empty : std_logic_vector(2 downto 0); signal lower_than_next : std_logic_vector(2 downto 0); signal pop : std_logic_vector(2 downto 0); function zpos ( constant zch : integer; signal idx : unsigned(idx_width-1 downto 0)) return unsigned is begin return conv_unsigned(zch + (conv_integer(idx) - 1) * 3, zpos_width); end; function sortnum ( constant zch : integer; signal idx : unsigned(idx_width-1 downto 0)) return integer is begin if conv_integer(idx) /= 0 then return positive(zch + (conv_integer(idx) - 1) * 3 + 1) / 2; else return 0; end if; end; begin mem_out(0) <= mem(0)(conv_integer(rd_addr_reg_0)); mem_out(1) <= mem(1)(conv_integer(rd_addr_reg_1)); mem_out(2) <= mem(2)(conv_integer(rd_addr_reg_2)); process (clk) begin if clk'event and clk = '1' then rd_addr_reg_0 <= next_rd_addr(0); rd_addr_reg_1 <= next_rd_addr(1); rd_addr_reg_2 <= next_rd_addr(2); end if; end process; process (pretrigger, pop, rd_addr_reg_0) begin if pretrigger = '1' then next_rd_addr(0) <= (mem_addr_width-1 downto 0 => '0'); elsif pop(0) = '1' then next_rd_addr(0) <= rd_addr_reg_0 + 1; else next_rd_addr(0) <= rd_addr_reg_0; end if; end process; process (pretrigger, pop, rd_addr_reg_1) begin if pretrigger = '1' then next_rd_addr(1) <= (mem_addr_width-1 downto 0 => '0'); elsif pop(1) = '1' then next_rd_addr(1) <= rd_addr_reg_1 + 1; else next_rd_addr(1) <= rd_addr_reg_1; end if; end process; process (pretrigger, pop, rd_addr_reg_2) begin if pretrigger = '1' then next_rd_addr(2) <= (mem_addr_width-1 downto 0 => '0'); elsif pop(2) = '1' then next_rd_addr(2) <= rd_addr_reg_2 + 1; else next_rd_addr(2) <= rd_addr_reg_2; end if; end process; not_empty(0) <= '1' when wr_addr_last(0) /= rd_addr_reg_0 else '0'; not_empty(1) <= '1' when wr_addr_last(1) /= rd_addr_reg_1 else '0'; not_empty(2) <= '1' when wr_addr_last(2) /= rd_addr_reg_2 else '0'; gen_ch : for ch in 2 downto 0 generate -- registers process (clk) begin if clk'event and clk = '1' then if pretrigger = '1' then wr_addr_reg(ch) <= (mem_addr_width-1 downto 0 => '0'); wr_addr_last(ch) <= (mem_addr_width-1 downto 0 => '0'); elsif valid_in(ch) = '1' then wr_addr_reg(ch) <= wr_addr_reg(ch) + 1; wr_addr_last(ch) <= wr_addr_reg(ch); end if; if valid_in(ch) = '1' then mem(ch)(conv_integer(wr_addr_reg(ch))) <= track_in(ch); end if; ready_in_reg(ch) <= ready_in(ch); end if; end process; mem_out_idx(ch) <= unsigned(mem_out(ch)(idx_high downto idx_low)); mem_out_y(ch) <= signed(mem_out(ch)(y_high downto y_low)); mem_out_sortnum(ch) <= sortnum(ch, mem_out_idx(ch)); mem_out_with_z(ch) <= std_logic_vector(zpos(ch, mem_out_idx(ch))) & mem_out(ch)(y_high downto 0); -- convenience signals lower_than_next(ch) <= '1' when mem_out_sortnum(ch) < mem_out_sortnum((ch+1) mod 3) or (mem_out_sortnum(ch) = mem_out_sortnum((ch+1) mod 3) and mem_out_y(ch) < mem_out_y((ch+1) mod 3)) else '0'; end generate; process (not_empty, lower_than_next, ready_in_reg) begin pop <= "000"; if (not_empty(2) = '1' or ready_in_reg(2) = '1') and (not_empty(1) = '1' or ready_in_reg(1) = '1') and (not_empty(0) = '1' or ready_in_reg(0) = '1') then case not_empty is when "000" => null; when "001" => pop(0) <= '1'; when "010" => pop(1) <= '1'; when "011" => if lower_than_next(0) = '1' then pop(0) <= '1'; else pop(1) <= '1'; end if; when "100" => pop(2) <= '1'; when "101" => if lower_than_next(2) = '1' then pop(2) <= '1'; else pop(0) <= '1'; end if; when "110" => if lower_than_next(1) = '1' then pop(1) <= '1'; else pop(2) <= '1'; end if; when "111" => if lower_than_next(0) = '1' then if lower_than_next(2) = '1' then pop(2) <= '1'; else pop(0) <= '1'; end if; else if lower_than_next(1) = '1' then pop(1) <= '1'; else pop(2) <= '1'; end if; end if; when others => null; end case; end if; end process; valid_out <= '1' when pop /= "000" else '0'; ready_out <= '1' when not_empty = "000" and ready_in_reg = "111" else '0'; process (pop, mem_out_with_z) begin if pop(2) = '1' then track_out <= mem_out_with_z(2); elsif pop(1) = '1' then track_out <= mem_out_with_z(1); else track_out <= mem_out_with_z(0); end if; end process; -- connect input signals track_in(2) <= track2_in; track_in(1) <= track1_in; track_in(0) <= track0_in; end;