--============================================================================= --! @file DUTInterfaces_rtl.vhd --============================================================================= -- ------------------------------------------------------------------------------- -- -- -- University of Bristol, High Energy Physics Group. -- -- ------------------------------------------------------------------------------- -- -- VHDL Architecture fmc_mTLU_lib.DUTInterfaces.rtl -- --! @brief \n --! \n -- --! @author David Cussans , David.Cussans@bristol.ac.uk -- --! @date 15:09:50 11/09/12 -- --! @version v0.1 -- --! @details --! Address map:\n --! 5-bit decoded --! 0x00000000 - DUT interface mode, two bits per DUT. Up to 12 inputs XXXXXXXXBBAA99887766554433221100\n --! - mode: 0 = EUDET mode , 1 = synchronous ( LHC / Timepix ) , 2,3=reserved --! -- --! --! Dependencies:\n --! --! References:\n --! --! Modified by:\n --! Author: ------------------------------------------------------------------------------- --! \n\nLast changes:\n ------------------------------------------------------------------------------- --! @todo Indicate if the DUT works under AIDA/EUDET style\n --! \n -- -------------------------------------------------------------------------------- -- -- Created using using Mentor Graphics HDL Designer(TM) 2010.3 (Build 21) -- LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.numeric_std.all; USE work.ipbus.all; use work.ipbus_reg_types.all; library unisim; use unisim.VComponents.all; ENTITY DUTInterfaces IS GENERIC( g_NUM_DUTS : positive := 3; g_IPBUS_WIDTH : positive := 32 ); PORT( busy_from_dut_n_i : IN std_logic_vector (g_NUM_DUTS-1 DOWNTO 0); -- BUSY input from DUTs busy_from_dut_p_i : IN std_logic_vector (g_NUM_DUTS-1 DOWNTO 0); -- BUSY input from DUTs clk_4x_logic_i : IN std_logic; ipbus_clk_i : IN std_logic; ipbus_i : IN ipb_wbus; -- Signals from IPBus core to slave ipbus_reset_i : IN std_logic; strobe_4x_logic_i : IN std_logic; -- ! goes high every 4th clock cycle --trigger_counter_i : IN std_logic_vector (g_IPBUS_WIDTH-1 DOWNTO 0); trigger_i : IN std_logic; -- goes high when trigger logic issues a trigger clk_to_dut_i : IN std_logic ; -- ! clock to DUT reset_or_clk_to_dut_i : IN std_logic; AIDAhandshake_i : IN std_logic; -- AIDA/EUDET handshake ipbus_o : OUT ipb_rbus; -- signals from slave to IPBus core clk_to_dut_n_o : INOUT std_logic_vector (g_NUM_DUTS-1 DOWNTO 0); -- clocks trigger data when in EUDET mode clk_to_dut_p_o : INOUT std_logic_vector (g_NUM_DUTS-1 DOWNTO 0); -- clocks trigger data when in EUDET mode reset_or_clk_to_dut_n_o : OUT std_logic_vector (g_NUM_DUTS-1 DOWNTO 0); -- ! Either reset line or trigger reset_or_clk_to_dut_p_o : OUT std_logic_vector (g_NUM_DUTS-1 DOWNTO 0); -- ! Either reset line or trigger trigger_to_dut_n_o : OUT std_logic_vector (g_NUM_DUTS-1 DOWNTO 0); -- ! Trigger output trigger_to_dut_p_o : OUT std_logic_vector (g_NUM_DUTS-1 DOWNTO 0); -- ! Trigger output veto_o : OUT std_logic -- goes high when one or more DUT are busy ); -- Declarations END ENTITY DUTInterfaces ; -- ARCHITECTURE rtl OF DUTInterfaces IS signal s_intermediate_busy_or : std_logic_vector(g_NUM_DUTS downto 0); -- OR tree signal s_veto : std_logic; signal s_strobe_4x_logic_d1 : std_logic; signal s_clk_to_DUT , s_busy_from_dut , s_reset_or_clk_to_dut , s_trigger_to_dut : std_logic_vector(g_NUM_DUTS-1 downto 0); signal s_DUT_mask : std_logic_vector(g_NUM_DUTS-1 downto 0) := (others => '0'); --! Mask for the DUTs not used signal s_clk_is_input, s_clk_is_input_b : std_logic := '0'; --! Indicates the direction of the clock in the RJ45 DUT signal s_clk_to_tlu : std_logic := '0'; constant c_N_CTRL : positive := 1; constant c_N_STAT : positive := 1; signal s_status_to_ipbus, s_sync_status_to_ipbus : ipb_reg_v(c_N_STAT-1 downto 0); signal s_control_from_ipbus,s_sync_control_from_ipbus : ipb_reg_v(c_N_CTRL-1 downto 0); BEGIN -- Dummy code. s_intermediate_busy_or(0) <= '0'; --s_busy_from_dut(g_NUM_DUTS-1 downto 0) <= (others=>'0'); ----------------------------------------------------------------------------- -- IPBus interface ----------------------------------------------------------------------------- ipbus_registers: entity work.ipbus_ctrlreg_v generic map( N_CTRL => c_N_CTRL, N_STAT => c_N_STAT ) port map( clk => ipbus_clk_i, reset=> '0',--ipbus_reset_i , ipbus_in=> ipbus_i, ipbus_out=> ipbus_o, d=> s_sync_status_to_ipbus, q=> s_control_from_ipbus, stb=> open ); -- Synchronize registers from logic clock to ipbus. sync_status: entity work.synchronizeRegisters generic map ( g_NUM_REGISTERS => c_N_STAT ) port map ( clk_input_i => clk_4x_logic_i, data_i => s_status_to_ipbus, data_o => s_sync_status_to_ipbus, clk_output_i => ipbus_clk_i); -- Synchronize registers from logic clock to ipbus. sync_ctrl: entity work.synchronizeRegisters generic map ( g_NUM_REGISTERS => c_N_CTRL ) port map ( clk_input_i => ipbus_clk_i, data_i => s_control_from_ipbus, data_o => s_sync_control_from_ipbus, clk_output_i => clk_4x_logic_i); -- Map the control registers s_DUT_mask <= s_sync_control_from_ipbus(0)(g_NUM_DUTS-1 downto 0); -- Map the status registers s_status_to_ipbus(0) <= std_logic_vector(to_unsigned(0,g_IPBUS_WIDTH-g_NUM_DUTS)) & s_DUT_mask; -- These instances need to be out of the loop because the RJ45 permits a bidirectional clock clk_to_DUT_OBUFDS_inst_0 : OBUFDS generic map ( IOSTANDARD => "LVDS_25") port map ( O => clk_to_dut_p_o(0), -- Diff_p output (connect directly to top-level port) OB => clk_to_dut_n_o(0), -- Diff_n output (connect directly to top-level port) I => s_clk_to_dut(0) -- Buffer output ); clk_to_DUT_OBUFDS_inst_1 : OBUFDS generic map ( IOSTANDARD => "LVDS_25") port map ( O => clk_to_dut_p_o(1), -- Diff_p output (connect directly to top-level port) OB => clk_to_dut_n_o(1), -- Diff_n output (connect directly to top-level port) I => s_clk_to_dut(1) -- Buffer output ); clk_to_DUT_OBUFDS_inst_2 : IOBUFDS generic map ( IOSTANDARD => "BLVDS_25") port map ( O => s_clk_to_tlu, -- Buffer output IO => clk_to_dut_p_o(2), -- Diff_p inout (connect directly to top-level port) IOB => clk_to_dut_n_o(2), -- Diff_n inout (connect directly to top-level port) I => s_clk_to_dut(2), -- Buffer input T => s_clk_is_input_b -- 3-state enable input, high=input, low=output ); s_clk_is_input <= not AIDAhandshake_i; --When an ODDR2 primitive is used in conjunction with a 3-state output, the T control pin must --also use an ODDR2 primitive configured in the same mode as the ODDR2 primitive used for data --output. ddr_for_clk_to_DUT_tristate : ODDR2 generic map( DDR_ALIGNMENT => "NONE", -- Sets output alignment to "NONE", "C0", "C1" INIT => '0', -- Sets initial state of the Q output to '0' or '1' SRTYPE => "SYNC") -- Specifies "SYNC" or "ASYNC" set/reset port map ( Q => s_clk_is_input_b, -- 1-bit output data C0 => clk_to_dut_i, -- 1-bit clock input C1 => not clk_to_dut_i, --not s_clk160_internal, -- 1-bit clock input CE => '1', -- 1-bit clock enable input D0 => s_clk_is_input, -- 1-bit data input (associated with C0) D1 => s_clk_is_input, -- 1-bit data input (associated with C1) R => '0', -- 1-bit reset input S => '0' -- 1-bit set input ); duts: for dut in 1 to g_NUM_DUTS generate busy_IBUFDS_inst : IBUFDS generic map ( DIFF_TERM => TRUE, -- Differential Termination IBUF_LOW_PWR => TRUE, -- Low power (TRUE) vs. performance (FALSE) setting for referenced I/O standards IOSTANDARD => "LVDS_25") port map ( O => s_busy_from_dut(dut-1), -- Buffer output I => busy_from_dut_p_i(dut-1), -- Diff_p buffer input (connect directly to top-level port) IB => busy_from_dut_n_i(dut-1) -- Diff_n buffer input (connect directly to top-level port) ); trig_OBUFDS_inst : OBUFDS generic map ( IOSTANDARD => "LVDS_25") port map ( O => trigger_to_dut_p_o(dut-1), -- Diff_p output (connect directly to top-level port) OB => trigger_to_dut_n_o(dut-1), -- Diff_n output (connect directly to top-level port) I => s_trigger_to_dut(dut-1) and s_DUT_mask(dut-1) -- Buffer input ); clk_rst_OBUFDS_inst : OBUFDS generic map ( IOSTANDARD => "LVDS_25") port map ( O => reset_or_clk_to_dut_p_o(dut-1), -- Diff_p output (connect directly to top-level port) OB => reset_or_clk_to_dut_n_o(dut-1), -- Diff_n output (connect directly to top-level port) I => reset_or_clk_to_dut_i --s_reset_or_clk_to_dut(dut-1) and s_DUT_mask(dut-1) -- Buffer input ); s_intermediate_busy_or(dut) <= s_intermediate_busy_or(dut-1) or (s_busy_from_dut(dut-1) and s_DUT_mask(dut-1)); ddr_for_clk_output : ODDR2 generic map( DDR_ALIGNMENT => "NONE", -- Sets output alignment to "NONE", "C0", "C1" INIT => '0', -- Sets initial state of the Q output to '0' or '1' SRTYPE => "SYNC") -- Specifies "SYNC" or "ASYNC" set/reset port map ( Q => s_clk_to_dut(dut-1), -- 1-bit output data C0 => clk_to_dut_i, -- 1-bit clock input C1 => not clk_to_dut_i, -- 1-bit clock input CE => '1', -- 1-bit clock enable input D0 => '1', -- 1-bit data input (associated with C0) D1 => '0', -- 1-bit data input (associated with C1) R => '0', -- 1-bit reset input S => '0' -- 1-bit set input ); end generate duts; s_veto <= s_intermediate_busy_or(g_NUM_DUTS); -- purpose: register for internal signals and output signals -- type : combinational -- inputs : clk_4x_logic_i , strobe_4x_logic_i , s_veto -- outputs: veto_o register_signals: process (clk_4x_logic_i)-- , strobe_4x_logic_i , s_veto) begin -- process register_signals if rising_edge(clk_4x_logic_i) then veto_o <= s_veto; s_strobe_4x_logic_d1 <= strobe_4x_logic_i; --s_reset_or_clk_to_dut <= ( others => (s_strobe_4x_logic_d1 or strobe_4x_logic_i)); s_trigger_to_dut <= ( others => trigger_i ); --shutter_to_dut <= ( others => shutter_i ); end if; end process register_signals; END ARCHITECTURE rtl;