--=============================================================================
--! @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;