Commit 1ed997b7 authored by David Cussans's avatar David Cussans

Merge branch 'dcussans/8bit_fine_ts' into 'master'

Dcussans/8bit fine ts

See merge request !2
parents d5da54ef 27f96930
......@@ -61,6 +61,7 @@ use work.ipbus_reg_types.all;
ENTITY eventFormatter IS
GENERIC(
g_EVENT_DATA_WIDTH : positive := 64;
g_COARSE_TIMESTAMP_WIDTH : positive := 48; -- ! Number of bits in 40MHz timestamp
g_IPBUS_WIDTH : positive := 32;
g_COUNTER_TRIG_WIDTH : positive := 32;
g_COUNTER_WIDTH : positive := 12;
......@@ -92,6 +93,7 @@ ENTITY eventFormatter IS
ipbus_o : OUT ipb_rbus;
data_strobe_o : OUT std_logic; --! goes high when data ready to load into event buffer
event_data_o : OUT std_logic_vector (g_EVENT_DATA_WIDTH-1 DOWNTO 0);
coarse_timestamp_o : OUT std_logic_vector (g_COARSE_TIMESTAMP_WIDTH-1 DOWNTO 0); --! Global timestamp. Clocked on clk_4x_logic, but only increments with logic_strobe
reset_timestamp_i : IN std_logic; --! Taking high causes timestamp to be reset. Combined with internal timestmap reset and written to reset_timestamp_o
reset_timestamp_o : OUT std_logic --! Goes high for one clock cycle of clk_4x_logic when timestamp reset
);
......@@ -134,8 +136,7 @@ ARCHITECTURE rtl OF eventFormatter IS
signal s_data_o : std_logic_vector(g_EVENT_DATA_WIDTH-1 DOWNTO 0); -- Multiplexed data from FIFOs
constant c_COARSE_TIMESTAMP_WIDTH : positive := 48; -- ! Number of bits in 40MHz timestamp
signal s_coarse_timestamp : std_logic_vector(c_COARSE_TIMESTAMP_WIDTH-1 downto 0) := (others => '0'); -- 40MHz timestamp.
signal s_coarse_timestamp : std_logic_vector(g_COARSE_TIMESTAMP_WIDTH-1 downto 0) := (others => '0'); -- 40MHz timestamp.
signal s_coarse_timestamp_ipbus : ipb_reg_v(1 downto 0) := ( others => (others => '0')); --! 40MHz timestamp on IPB clock domain.
-- signal s_event_number : unsigned(g_IPBUS_WIDTH-1 downto 0) := (others => '0'); -- increment after each post-veto trigger.
......@@ -327,8 +328,8 @@ BEGIN
s_word0_p1 <= s_evttype & s_var & s_coarse_timestamp;
s_word1 <= "000" & trigger_times_d1(0) & "000" & trigger_times_d1(1) &
"000" & trigger_times_d1(2) & "000" & trigger_times_d1(3) &
s_word1 <= trigger_times_d1(0) & trigger_times_d1(1) &
trigger_times_d1(2) & trigger_times_d1(3) &
trigger_cnt_i;
......@@ -375,7 +376,8 @@ BEGIN
enable_i => logic_strobe_i,
result_o => s_coarse_timestamp);
coarse_timestamp_o <= s_coarse_timestamp;
-- Generate data in format decided at DESY. Put out two strobes for the
-- two 64 bit words.
-- get trigger inputs to also generate a global time-stamp ??
......
......@@ -13,11 +13,13 @@ LIBRARY ieee;
USE ieee.std_logic_1164.all;
PACKAGE fmcTLU IS
constant c_NUM_TIME_BITS : natural := 5;
constant c_NUM_TIME_BITS : natural := 8;
constant c_NUM_TRIG_INPUTS : natural := 4;
constant c_EVENT_DATA_WIDTH : natural := 32;
constant c_DATA_WIDTH : natural := 32;
constant c_COARSE_TIMESTAMP_WIDTH : natural := 48;
constant c_TRIGIN_NUM_COARSE_TS_BITS : natural := 3;
subtype t_triggerTime is std_logic_vector(c_NUM_TIME_BITS-1 downto 0);
--type t_triggerTimeArray is array(natural range <>) of t_triggerTime;
type t_triggerTimeArray is array(natural range <>) of std_logic_vector(c_NUM_TIME_BITS-1 downto 0) ;
......
......@@ -27,11 +27,11 @@
------------------------------------------------------------------------------
-- __primary__________40.000____________0.010
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
USE work.ipbus.all;
use work.ipbus.all;
library unisim;
use unisim.vcomponents.all;
......@@ -54,200 +54,260 @@ use unisim.vcomponents.all;
--! \li 0x00000001 - reset logic. Write to bit-zero to send reset.
--!
--!
ENTITY logic_clocks IS
GENERIC(
g_USE_EXTERNAL_CLK : integer := 1
entity logic_clocks is
generic(
g_USE_EXTERNAL_CLK : integer := 1
);
PORT(
ipbus_clk_i : IN std_logic;
ipbus_i : IN ipb_wbus;
ipbus_reset_i : IN std_logic;
Reset_i : IN std_logic;
clk_logic_xtal_i : IN std_logic; --! 40MHz clock derived from onboard xtal
clk_8x_logic_o : OUT std_logic; --! 640MHz clock
clk_4x_logic_o : OUT std_logic; --! 160MHz clock
ipbus_o : OUT ipb_rbus;
strobe_8x_logic_o : OUT std_logic; --! strobes once every 4 cycles of clk_16x
strobe_4x_logic_o : OUT std_logic; --! one pulse every 4 cycles of clk_4x
DUT_clk_o : OUT std_logic; --! 40MHz to DUTs
logic_clocks_locked_o : OUT std_logic; --! Goes high if clocks locked.
logic_reset_o : OUT std_logic --! Goes high to reset counters etc. Sync with clk_4x_logic
port(
ipbus_clk_i : in std_logic;
ipbus_i : in ipb_wbus;
ipbus_reset_i : in std_logic;
Reset_i : in std_logic;
clk_logic_xtal_i : in std_logic; --! 40MHz clock derived from onboard xtal
clk_8x_logic_o : out std_logic; --! 640MHz clock
clk_4x_logic_o : out std_logic; --! 160MHz clock
ipbus_o : out ipb_rbus;
strobe_8x_logic_o : out std_logic; --! strobes once every 4 cycles of clk_16x
strobe_4x_logic_o : out std_logic; --! one pulse every 4 cycles of clk_4x
DUT_clk_o : out std_logic; --! 40MHz to DUTs
logic_clocks_locked_o : out std_logic; --! Goes high if clocks locked.
logic_reset_o : out std_logic --! Goes high to reset counters etc. Sync with clk_4x_logic
);
-- Declarations
END ENTITY logic_clocks ;
end entity logic_clocks;
--
ARCHITECTURE rtl OF logic_clocks IS
signal s_clk40 : std_logic;
constant C_NUM_STROBE_TAPS : positive := 2; --! Adjust to shift strobes relative to 40MHz clock edge
signal s_clk40_delayed_160 : std_logic_vector(C_NUM_STROBE_TAPS downto 0); --! Shift register used to generate clock_4x strobe. Adjust length for correct alignment with incoming clock
signal s_clk40_delayed_320 : std_logic_vector((2*C_NUM_STROBE_TAPS)+1 downto 0); --! Shift register used to generate clock_8x strobe. Adjust length for correct alignment with incoming clock
signal s_clk160 ,s_clk160_internal : std_logic;
signal s_clk320 , s_clk320_internal : std_logic;
signal s_locked_pll : std_logic;
signal s_clk : std_logic;
signal s_DUT_Clk : std_logic;
signal s_clkfbout : std_logic;
signal s_logic_reset_ipb, s_logic_reset_ipb_d1 : std_logic := '0'; --! Reset signal in IPBus clock domain
signal s_logic_reset , s_logic_reset_d1 , s_logic_reset_d2 , s_logic_reset_d3 , s_logic_reset_d4 : std_logic := '0'; --! reset signal clocked onto logic-clock domain.
attribute SHREG_EXTRACT: string;
attribute SHREG_EXTRACT of s_logic_reset_d1: signal is "no"; -- Synchroniser not to be optimised into shreg
attribute SHREG_EXTRACT of s_logic_reset_d2: signal is "no"; -- Synchroniser not to be optimised into shreg
attribute SHREG_EXTRACT of s_logic_reset_d3: signal is "no"; -- Synchroniser not to be optimised into shreg
attribute SHREG_EXTRACT of s_logic_reset_d4: signal is "no"; -- Synchroniser not to be optimised into shreg
attribute SHREG_EXTRACT of s_clk40_delayed_160: signal is "no"; -- delay to help timing not to be optimised into shreg
attribute SHREG_EXTRACT of s_clk40_delayed_320: signal is "no"; -- delay to help timing not to be optimised into shreg
signal s_ipbus_ack : std_logic := '0';
signal s_reset_pll : std_logic := '0'; -- ! PLL Reset signal
signal s_clock_status_ipb : std_logic_vector( ipbus_o.ipb_rdata'range ); --! contains status of clocks
BEGIN
-----------------------------------------------------------------------------
-- IPBus write
-----------------------------------------------------------------------------
ipbus_write: process (ipbus_clk_i)
begin -- process ipb_clk_i
architecture rtl of logic_clocks is
signal s_clk40 : std_logic;
constant C_NUM_STROBE_TAPS : positive := 2; --! Adjust to shift strobes relative to 40MHz clock edge
signal s_clk40_delayed_160 : std_logic_vector(C_NUM_STROBE_TAPS downto 0); --! Shift register used to generate clock_4x strobe. Adjust length for correct alignment with incoming clock
signal s_clk40_delayed_320 : std_logic_vector((2*C_NUM_STROBE_TAPS)+1 downto 0); --! Shift register used to generate clock_8x strobe. Adjust length for correct alignment with incoming clock
signal s_clk160, s_clk160_internal : std_logic;
signal s_clk320, s_clk320_internal : std_logic;
signal s_locked_pll : std_logic;
signal s_clk : std_logic;
signal s_DUT_Clk : std_logic;
signal s_clkfbout : std_logic;
signal s_logic_reset_ipb, s_logic_reset_ipb_d1 : std_logic := '0'; --! Reset signal in IPBus clock domain
signal s_logic_reset, s_logic_reset_d1, s_logic_reset_d2, s_logic_reset_d3, s_logic_reset_d4 : std_logic := '0'; --! reset signal clocked onto logic-clock domain.
attribute SHREG_EXTRACT : string;
attribute SHREG_EXTRACT of s_logic_reset_d1 : signal is "no"; -- Synchroniser not to be optimised into shreg
attribute SHREG_EXTRACT of s_logic_reset_d2 : signal is "no"; -- Synchroniser not to be optimised into shreg
attribute SHREG_EXTRACT of s_logic_reset_d3 : signal is "no"; -- Synchroniser not to be optimised into shreg
attribute SHREG_EXTRACT of s_logic_reset_d4 : signal is "no"; -- Synchroniser not to be optimised into shreg
attribute SHREG_EXTRACT of s_clk40_delayed_160 : signal is "no"; -- delay to help timing not to be optimised into shreg
attribute SHREG_EXTRACT of s_clk40_delayed_320 : signal is "no"; -- delay to help timing not to be optimised into shreg
signal s_ipbus_ack : std_logic := '0';
signal s_reset_pll : std_logic := '0'; -- ! PLL Reset signal
signal s_clock_status_ipb : std_logic_vector(ipbus_o.ipb_rdata'range); --! contains status of clocks
signal s_enable_strobes : std_logic; -- take high to start strobes running.
begin
-----------------------------------------------------------------------------
-- IPBus write
-----------------------------------------------------------------------------
ipbus_write : process (ipbus_clk_i)
begin -- process ipb_clk_i
if rising_edge(ipbus_clk_i) then
s_logic_reset_ipb <= '0';
if (ipbus_i.ipb_strobe = '1' and ipbus_i.ipb_write = '1') then
case ipbus_i.ipb_addr(1 downto 0) is
when "01" =>
s_logic_reset_ipb <= ipbus_i.ipb_wdata(0) ; -- write to reset
when others => null;
end case;
end if;
-- register reset signal to aid timing.
s_logic_reset_ipb_d1 <= s_logic_reset_ipb;
s_ipbus_ack <= ipbus_i.ipb_strobe and not s_ipbus_ack;
-- register the clock status signals onto IPBus domain.
s_clock_status_ipb <= x"0000000" & '0' & '0' & '0' & s_locked_pll; -- The only useful bit is now the PLL lock status.
s_logic_reset_ipb <= '0';
if (ipbus_i.ipb_strobe = '1' and ipbus_i.ipb_write = '1') then
case ipbus_i.ipb_addr(1 downto 0) is
when "01" =>
s_logic_reset_ipb <= ipbus_i.ipb_wdata(0); -- write to reset
when others => null;
end case;
end if;
-- register reset signal to aid timing.
s_logic_reset_ipb_d1 <= s_logic_reset_ipb;
s_ipbus_ack <= ipbus_i.ipb_strobe and not s_ipbus_ack;
-- register the clock status signals onto IPBus domain.
s_clock_status_ipb <= x"0000000" & '0' & '0' & '0' & s_locked_pll; -- The only useful bit is now the PLL lock status.
end if;
end process ipbus_write;
end process ipbus_write;
ipbus_o.ipb_ack <= s_ipbus_ack;
ipbus_o.ipb_err <= '0';
ipbus_o.ipb_ack <= s_ipbus_ack;
ipbus_o.ipb_err <= '0';
-----------------------------------------------------------------------------
-- IPBUS read
-----------------------------------------------------------------------------
with ipbus_i.ipb_addr(1 downto 0) select
-----------------------------------------------------------------------------
-- IPBUS read
-----------------------------------------------------------------------------
with ipbus_i.ipb_addr(1 downto 0) select
ipbus_o.ipb_rdata <=
s_clock_status_ipb when "00",
(others => '1') when others;
s_clock_status_ipb when "00",
(others => '1') when others;
-----------------------------------------------------------------------------
-- Generate reset signal on logic-clock domain
-- This relies on the IPBus clock being much slower than the 4x logic clock.
-----------------------------------------------------------------------------
p_reset: process (s_clk160_internal)
begin -- process p_reset
-----------------------------------------------------------------------------
-- Generate reset signal on logic-clock domain
-- This relies on the IPBus clock being much slower than the 4x logic clock.
-----------------------------------------------------------------------------
p_reset : process (s_clk160_internal)
begin -- process p_reset
if rising_edge(s_clk160_internal) then
s_logic_reset_d1 <= s_logic_reset_ipb_d1;
s_logic_reset_d2 <= s_logic_reset_d1;
s_logic_reset_d3 <= s_logic_reset_d2;
s_logic_reset_d4 <= s_logic_reset_d2 and ( not s_logic_reset_d3);
s_logic_reset <= s_logic_reset_d4;
s_logic_reset_d1 <= s_logic_reset_ipb_d1;
s_logic_reset_d2 <= s_logic_reset_d1;
s_logic_reset_d3 <= s_logic_reset_d2;
s_logic_reset_d4 <= s_logic_reset_d2 and (not s_logic_reset_d3);
s_logic_reset <= s_logic_reset_d4;
end if;
end process p_reset;
logic_reset_o <= s_logic_reset;
logic_clocks_locked_o <= s_locked_pll;
s_DUT_Clk <= clk_logic_xtal_i;
--! Clocking primitive
-------------------------------------
--! Instantiation of the PLL primitive
pll_base_inst : PLL_BASE
end process p_reset;
logic_reset_o <= s_logic_reset or (not s_locked_pll);
logic_clocks_locked_o <= s_locked_pll;
s_DUT_Clk <= clk_logic_xtal_i;
--! Clocking primitive
-------------------------------------
--! Instantiation of the PLL primitive
pll_base_inst : PLL_BASE
generic map
(BANDWIDTH => "OPTIMIZED",
CLK_FEEDBACK => "CLKFBOUT",
COMPENSATION => "SYSTEM_SYNCHRONOUS",
DIVCLK_DIVIDE => 1,
CLKFBOUT_MULT => 16, -- Run PLL at 640MHz
CLKFBOUT_PHASE => 0.000,
CLKOUT0_DIVIDE => 2, -- CLK0 = 320MHz
CLKOUT0_PHASE => 0.000,
CLKOUT0_DUTY_CYCLE => 0.500,
CLKOUT1_DIVIDE => 4, -- CLK1 = 160MHz
CLKOUT1_PHASE => 0.000,
CLKOUT1_DUTY_CYCLE => 0.500,
CLKOUT2_DIVIDE => 16, -- CLK2 = 40MHz
CLKOUT2_PHASE => +16.900, -- Shift 40MHz clock later to avoid negative hold time in strobe generator
CLKOUT2_DUTY_CYCLE => 0.500,
CLKIN_PERIOD => 25.000,
REF_JITTER => 0.010)
(BANDWIDTH => "OPTIMIZED",
CLK_FEEDBACK => "CLKFBOUT",
COMPENSATION => "SYSTEM_SYNCHRONOUS",
DIVCLK_DIVIDE => 1,
CLKFBOUT_MULT => 16, -- Run PLL at 640MHz
CLKFBOUT_PHASE => 0.000,
CLKOUT0_DIVIDE => 2, -- CLK0 = 320MHz
CLKOUT0_PHASE => 0.000,
CLKOUT0_DUTY_CYCLE => 0.500,
CLKOUT1_DIVIDE => 4, -- CLK1 = 160MHz
CLKOUT1_PHASE => 0.000,
CLKOUT1_DUTY_CYCLE => 0.500,
CLKOUT2_DIVIDE => 16, -- CLK2 = 40MHz
CLKOUT2_PHASE => +16.875, -- Shift 40MHz clock later to avoid negative hold time in strobe generator
CLKOUT2_DUTY_CYCLE => 0.500,
CLKIN_PERIOD => 25.000,
REF_JITTER => 0.010)
port map(
-- Output clocks
CLKFBOUT => s_clkfbout,
CLKOUT0 => s_clk320,
CLKOUT1 => s_clk160,
CLKOUT2 => s_clk40,
CLKOUT3 => open,
CLKOUT4 => open,
CLKOUT5 => open,
-- Status and control signals
LOCKED => s_locked_pll,
RST => s_reset_pll,
-- Input clock control
CLKFBIN => s_clkfbout,
CLKIN => s_DUT_clk);
-- Output clocks
CLKFBOUT => s_clkfbout,
CLKOUT0 => s_clk320,
CLKOUT1 => s_clk160,
CLKOUT2 => s_clk40,
CLKOUT3 => open,
CLKOUT4 => open,
CLKOUT5 => open,
-- Status and control signals
LOCKED => s_locked_pll,
RST => s_reset_pll,
-- Input clock control
CLKFBIN => s_clkfbout,
CLKIN => s_DUT_clk);
-- TODO: Replace PLL_BASE ( Spartan6 etc. with PLLE2_ADV - synthesis tools
-- seem to cope but ........
-- plle2_adv_instL PLLE2_ADV
-- generic map
-- (BANDWIDTH => "OPTIMIZED",
-- COMPENSATION => "ZHOLD",
-- STARTUP_WAIT => "FALSE",
-- DIVCLK_DIVIDE => 1,
-- CLKFBOUT_MULT => 24,
-- CLKFBOUT_PHASE => 0.000,
-- CLKOUT0_DIVIDE => 3,
-- CLKOUT0_PHASE => 0.000,
-- CLKOUT0_DUTY_CYCLE => 0.500,
-- CLKOUT1_DIVIDE => 6,
-- CLKOUT1_PHASE => 0.000,
-- CLKOUT1_DUTY_CYCLE => 0.500,
-- CLKOUT2_DIVIDE => 24,
-- CLKOUT2_PHASE => 16.875,
-- CLKOUT2_DUTY_CYCLE => 0.500,
-- CLKIN1_PERIOD => 25.000)
-- port map (
-- .CLKFBOUT => s_clkfbout ,
-- .CLKOUT0 => s_clk320,
-- .CLKOUT1 => s_clk160,
-- .CLKOUT2 => s_clk40,
-- .CLKOUT3 => open,
-- .CLKOUT4 => open,
-- .CLKOUT5 => open,
-- // Input clock control
-- .CLKFBIN => s_clkfbout ,
-- .CLKIN1 => s_DUT_clk,
-- .CLKIN2 => '0',
-- -- Tied to always select the primary input clock
-- .CLKINSEL => '1',
-- -- Ports for dynamic reconfiguration
-- .DADDR => (others => '0') ,
-- .DCLK => '0',
-- .DEN => '0',
-- .DI => (others => '0') ,
-- .DO => open ,
-- .DRDY => open,
-- .DWE => '0',
-- -- Other control and status signals
-- .LOCKED => s_locked_pll,
-- .PWRDWN => '0',
-- .RST => s_clkfbout );
s_reset_pll <= Reset_i or s_logic_reset;
s_reset_pll <= Reset_i or s_logic_reset;
DUT_clk_o <= s_DUT_clk;
DUT_clk_o <= s_DUT_clk;
s_enable_strobes <= s_locked_pll when rising_edge(s_clk40);
-- Generate a strobe signal for 160MHz clock
generate_4x_strobe: process (s_clk160_internal, s_clk40)
begin -- process generate_4x_strobe
if rising_edge(s_clk160_internal) then
generate_4x_strobe : process (s_clk160_internal, s_clk40)
begin -- process generate_4x_strobe
if rising_edge(s_clk160_internal) then
if (s_enable_strobes = '0') then
s_clk40_delayed_160 <= (others => '0');
strobe_4x_logic_o <= '0';
else
s_clk40_delayed_160 <= s_clk40_delayed_160(s_clk40_delayed_160'left-1 downto 0) & s_clk40;
strobe_4x_logic_o <= s_clk40_delayed_160(s_clk40_delayed_160'left-1) and not s_clk40_delayed_160(s_clk40_delayed_160'left);
strobe_4x_logic_o <= s_clk40_delayed_160(s_clk40_delayed_160'left-1) and not s_clk40_delayed_160(s_clk40_delayed_160'left);
end if;
end process generate_4x_strobe;
end if;
end process generate_4x_strobe;
-- Generate a strobe signal for 160MHz clock
generate_8x_strobe: process (s_clk160_internal, s_clk40)
begin -- process generate_4x_strobe
if rising_edge(s_clk320_internal) then
-- Generate a strobe signal for 320MHz clock
generate_8x_strobe : process (s_clk320_internal, s_clk40)
begin -- process generate_8x_strobe
if rising_edge(s_clk320_internal) then
if (s_enable_strobes = '0') then
s_clk40_delayed_320 <= (others => '0');
strobe_8x_logic_o <= '0';
else
s_clk40_delayed_320 <= s_clk40_delayed_320(s_clk40_delayed_320'left-1 downto 0) & s_clk40;
strobe_8x_logic_o <= s_clk40_delayed_320(s_clk40_delayed_320'left-1) and not s_clk40_delayed_320(s_clk40_delayed_320'left);
strobe_8x_logic_o <= s_clk40_delayed_320(s_clk40_delayed_320'left-1) and not s_clk40_delayed_320(s_clk40_delayed_320'left);
end if;
end process generate_8x_strobe;
end if;
end process generate_8x_strobe;
-- buffer 160MHz (4x) clock
--------------------------------------
clk160_o_buf : BUFG
clk160_o_buf : BUFG
port map(
O => s_clk160_internal,
I => s_clk160);
clk_4x_logic_o <= s_clk160_internal;
O => s_clk160_internal,
I => s_clk160);
clk_4x_logic_o <= s_clk160_internal;
-- buffer 320MHz (8x) clock
--------------------------------------
clk320_o_buf: BUFG
clk320_o_buf : BUFG
port map (
I => s_clk320,
O => s_clk320_internal
);
clk_8x_logic_o <= s_clk320_internal;
END ARCHITECTURE rtl;
I => s_clk320,
O => s_clk320_internal
);
clk_8x_logic_o <= s_clk320_internal;
end architecture rtl;
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 17.02.2017 11:26:56
-- Design Name:
-- Module Name: testbench_clocks - Behavioral
-- Project Name:
-- Target Devices:
-- Tool Versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity testbench_clocks is
-- Port ( );
end testbench_clocks;
architecture Behavioral of testbench_clocks is
begin
end Behavioral;
......@@ -163,19 +163,10 @@ BEGIN
end process examine_lut;
--! Coarse time stamp. Phase w.r.t. strobe
-- c_coarse_ts : entity work.CounterUp
-- PORT MAP (
-- clk => clk_4x_logic_i,
-- ce => '1',
-- sinit => strobe_4x_logic_i, --'0',
-- q(31 downto 2) => open,
-- q(1 downto 0) => s_coarse_bits
-- );
--
c_coarse_ts : entity work.CounterWithReset
GENERIC MAP (
g_COUNTER_WIDTH => 2 )
g_COUNTER_WIDTH => 2,
g_OUTPUT_REGISTERS => 3)
PORT MAP (
clock_i => clk_4x_logic_i,
enable_i => '1',
......
......@@ -120,24 +120,7 @@ BEGIN
);
-----------------------------------------------------
-- iodelay_prompt : delayIO
-- port map
-- (
-- data_in_from_pins_p(0) => data_i_pos,
-- data_in_from_pins_n(0) => data_i_neg,
-- data_in_to_device(0) => s_Data_i_d_p,
-- delay_clk => fabricClk_i,
-- in_delay_reset => '0',
-- in_delay_data_ce(0) => '1',
-- in_delay_data_inc(0) => '0',
-- delay_locked => open,
-- ref_clock => fabricClk_i,
-- clk_in => fastClk_i,
-- clock_enable => '1',
-- io_reset => s_rst_cal
-- );
prompt_val <= "00000";
IDELAY2_Prompt : IDELAYE2
......@@ -163,61 +146,13 @@ BEGIN
);
----IODELAY2 no longer valid. Replaced using IP delay (SelectIO interface wizard generated)
-- IODELAY2_Prompt : IODELAY2
-- generic map (
-- COUNTER_WRAPAROUND => "STAY_AT_LIMIT" , -- "STAY_AT_LIMIT" or "WRAPAROUND"
-- DATA_RATE => "SDR", -- "SDR" or "DDR"
-- DELAY_SRC => "IDATAIN", -- "IO", "ODATAIN" or "IDATAIN"
-- SERDES_MODE => "NONE", -- <NONE>, MASTER, SLAVE
-- IDELAY_TYPE => "VARIABLE_FROM_ZERO",
-- IDELAY_VALUE => 0 -- Amount of taps for fixed input delay (0-255)
-- --SIM_TAPDELAY_VALUE=> 10 -- Per tap delay used for simulation in ps
-- )
-- port map (
-- BUSY => s_busy_idelay_p, -- 1-bit output: Busy output after CAL
-- DATAOUT => s_Data_i_d_p, -- 1-bit output: Delayed data output to ISERDES/input register
-- DATAOUT2 => open, -- 1-bit output: Delayed data output to general FPGA fabric
-- DOUT => open, -- 1-bit output: Delayed data output
-- TOUT => open, -- 1-bit output: Delayed 3-state output
-- CAL => s_cal, -- 1-bit input: Initiate calibration input
-- CE => '0', -- 1-bit input: Enable INC input
-- CLK => fabricClk_i, -- 1-bit input: Clock input
-- IDATAIN => data_i, -- 1-bit input: Data input (connect to top-level port or I/O buffer)
-- INC => '0', -- 1-bit input: Increment / decrement input
-- IOCLK0 => fastClk_i, -- 1-bit input: Input from the I/O clock network
-- IOCLK1 => '0', -- 1-bit input: Input from the I/O clock network
-- ODATAIN => '0', -- 1-bit input: Output data input from output register or OSERDES2.
-- RST => s_rst_cal, -- 1-bit input: reset_i to 1/2 of total delay period
-- T => '1' -- 1-bit input: 3-state input signal
-- );
s_busy_idelay_p <= (prompt_val(0) XOR prompt_out(0)) OR (prompt_val(1) XOR prompt_out(1)) OR (prompt_val(2) XOR prompt_out(2)) OR (prompt_val(3) XOR prompt_out(3)) OR (prompt_val(4) XOR prompt_out(4));
status_o(1) <= s_busy_idelay_p;
-- iodelay_delay : delayIO
-- port map
-- (
-- data_in_from_pins_p(0) => data_i_pos,
-- data_in_from_pins_n(0) => data_i_neg,
-- data_in_to_device(0) => s_Data_i_d_d,
-- delay_clk => fabricClk_i,
-- in_delay_reset => '0',
-- in_delay_data_ce(0) => '1',
-- in_delay_data_inc(0) => '0',
-- delay_locked => open,
-- ref_clock => fabricClk_i,
-- clk_in => fastClk_i,
-- clock_enable => '1',
-- clk_out => open,
-- io_reset => s_rst_cal
-- );
-- This should be configurable via IPBus. For now fixed value. The tap value is 200 MHz (5 ns). We want
-- a quarter of the 320 MHz clock (3.125 ns) so 0.78125 ns, corresponding to 6 taps.
delay_val <= "00110";
-- This should be configurable via IPBus. For now fixed value. The tap value at 200 MHz (5
-- ns) is 78ps . We want a quarter of the 320 MHz clock (3.125 ns) so 0.78125 ns, corresponding to 10 taps.
delay_val <= "01010";
--delay_val <= "00000";
IDELAY2_Delayed : IDELAYE2
......@@ -244,36 +179,6 @@ BEGIN
);
-- IODELAY2_Delayed : IODELAY2
-- generic map (
-- COUNTER_WRAPAROUND => "STAY_AT_LIMIT", -- "STAY_AT_LIMIT" or "WRAPAROUND"
-- DATA_RATE => "SDR", -- "SDR" or "DDR"
-- DELAY_SRC => "IDATAIN", -- "IO", "ODATAIN" or "IDATAIN"
-- SERDES_MODE => "NONE", -- <NONE>, MASTER, SLAVE
-- IDELAY_TYPE => "VARIABLE_FROM_HALF_MAX",
-- IDELAY_VALUE => 0, -- Amount of taps for fixed input delay (0-255)
-- IDELAY2_VALUE => 0 -- Delay value when IDELAY_MODE="PCI" (0-255)
-- --SIM_TAPDELAY_VALUE => 10 -- Per tap delay used for simulation in ps
-- )
-- port map (
-- BUSY => s_busy_idelay_d, -- 1-bit output: Busy output after CAL
-- DATAOUT => s_Data_i_d_d, -- 1-bit output: Delayed data output to ISERDES/input register
-- DATAOUT2 => open, -- 1-bit output: Delayed data output to general FPGA fabric
-- DOUT => open, -- 1-bit output: Delayed data output
-- TOUT => open, -- 1-bit output: Delayed 3-state output
-- CAL => s_cal, -- 1-bit input: Initiate calibration input
-- CE => '0', -- 1-bit input: Enable INC input
-- CLK => fabricClk_i, -- 1-bit input: Clock input
-- IDATAIN => data_i, -- 1-bit input: Data input (connect to top-level port or I/O buffer)
-- INC => '0', -- 1-bit input: Increment / decrement input
-- IOCLK0 => fastClk_i, -- 1-bit input: Input from the I/O clock network
-- IOCLK1 => '0', -- 1-bit input: Input from the I/O clock network
-- ODATAIN => '0', -- 1-bit input: Output data input from output register or OSERDES2.
-- RST => s_rst_cal, -- 1-bit input: reset_i to zero
-- T => '1' -- 1-bit input: 3-state input signal
-- );
--I must check that the CNTVALUEOUT and CNTVALUEIN are the same. TO DO
--status_o(0) <= s_busy_idelay_d;
s_busy_idelay_d <= (delay_val(0) XOR delayed_out(0)) OR (delay_val(1) XOR delayed_out(1)) OR (delay_val(2) XOR delayed_out(2)) OR (delay_val(3) XOR delayed_out(3)) OR (delay_val(4) XOR delayed_out(4));
......@@ -281,35 +186,6 @@ BEGIN
s_busy <= s_busy_idelay_p or s_busy_idelay_d;
-----------------------------------------------------
--ISERDES2 replaced by ISERDESE2 in Series 7
-- ISERDES2_Prompt : ISERDES2
-- generic map (
-- BITSLIP_ENABLE => FALSE, -- Enable Bitslip Functionality (TRUE/FALSE)
-- DATA_RATE => "SDR", -- Data-rate ("SDR" or "DDR")
-- DATA_WIDTH => 4, -- Parallel data width selection (2-8)
-- INTERFACE_TYPE => "RETIMED", -- "NETWORKING", "NETWORKING_PIPELINED" or "RETIMED"
-- SERDES_MODE => "NONE" -- "NONE", "MASTER" or "SLAVE"
-- )
-- port map (
-- -- Q1 - Q4: 1-bit (each) output Registered outputs to FPGA logic
-- Q1 => s_Data_o(1), -- Oldest data
-- Q2 => s_Data_o(3),
-- Q3 => s_Data_o(5),
-- Q4 => s_Data_o(7), -- most recent data
-- --SHIFTOUT => SHIFTOUTsig, -- 1-bit output Cascade output signal for master/slave I/O
-- VALID => open, -- 1-bit output Output status of the phase detector
-- BITSLIP => '0', -- 1-bit input Bitslip enable input
-- CE0 => '1', -- 1-bit input Clock enable input
-- CLK0 => fastClk_i, -- 1-bit input I/O clock network input
-- CLK1 => '0', -- 1-bit input Secondary I/O clock network input
-- CLKDIV => fabricClk_i, -- 1-bit input FPGA logic domain clock input
-- D => s_Data_i_d_p, -- 1-bit input Input data
-- IOCE => strobe_i, -- 1-bit input Data strobe_i input
-- RST => reset_i, -- 1-bit input Asynchronous reset_i input
-- SHIFTIN => '0' -- 1-bit input Cascade input signal for master/slave I/O
-- );
ISERDESE2_Prompt: ISERDESE2 --Used to replace ISERDES2. Best of luck with it.
generic map (
DATA_RATE => "DDR",
......@@ -345,33 +221,7 @@ BEGIN
OFB=> '0'
);
-- ISERDES2_Delayed : ISERDES2
-- generic map (
-- BITSLIP_ENABLE => FALSE, -- Enable Bitslip Functionality (TRUE/FALSE)
-- DATA_RATE => "SDR", -- Data-rate ("SDR" or "DDR")
-- DATA_WIDTH => 4, -- Parallel data width selection (2-8)
-- INTERFACE_TYPE => "RETIMED", -- "NETWORKING", "NETWORKING_PIPELINED" or "RETIMED"
-- SERDES_MODE => "NONE" -- "NONE", "MASTER" or "SLAVE"
-- )
-- port map (
-- -- Q1 - Q4: 1-bit (each) output Registered outputs to FPGA logic
-- Q1 => s_Data_o(0), -- oldest data
-- Q2 => s_Data_o(2),
-- Q3 => s_Data_o(4),
-- Q4 => s_Data_o(6), -- most recent data
-- --SHIFTOUT => SHIFTOUTsig, -- 1-bit output Cascade output signal for master/slave I/O
-- VALID => open, -- 1-bit output Output status of the phase detector
-- BITSLIP => '0', -- 1-bit input Bitslip enable input
-- CE0 => '1', -- 1-bit input Clock enable input
-- CLK0 => fastClk_i, -- 1-bit input I/O clock network input
-- CLK1 => '0', -- 1-bit input Secondary I/O clock network input
-- CLKDIV => fabricClk_i, -- 1-bit input FPGA logic domain clock input
-- D => s_Data_i_d_d, -- 1-bit input Input data
-- IOCE => strobe_i, -- 1-bit input Data strobe_i input
-- RST => reset_i, -- 1-bit input Asynchronous reset_i input
-- SHIFTIN => '0' -- 1-bit input Cascade input signal for master/slave I/O
-- );
ISERDESE2_Delayed: ISERDESE2 --Used to replace ISERDES2. Best of luck with it.
generic map (
......
......@@ -37,6 +37,7 @@ use unisim.vcomponents.all;
--!
--! @details
--! \li IPBus address 0 = control and status
--! \li write -->
--! \li bit0 = reset serdes
--! \li bit1 = reset counter
--! \li bit2 = calibrate IDELAYs
......@@ -71,6 +72,7 @@ use unisim.vcomponents.all;
--! \li IPBus address 3 = edge rising(2) counter
--! \li IPBus address 4 = edge rising(3) counter
--!
--! \li Address 1 = invert input bits 5..0. Set 1 to select for negative going pulses.
--!
--! <b>Modified by: Alvaro Dosil , alvaro.dosil@usc.es </b>\n
--! Author:
......@@ -82,7 +84,8 @@ use unisim.vcomponents.all;
ENTITY triggerInputs_newTLU IS
GENERIC(
g_NUM_INPUTS : natural := 1;--1
g_NUM_INPUTS : natural := 1;--1
g_NUM_COARSE_TS_BITS : natural := 3; --! Number of coarse ( clk_1x_logic normally 40MHz ) timestamp bits to add to MSB of trigger times.
g_IPBUS_WIDTH : positive := 32
);
PORT(
......@@ -94,6 +97,7 @@ ENTITY triggerInputs_newTLU IS
threshold_discr_p_i : IN std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0); --! inputs from threshold comparators
threshold_discr_n_i : IN std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0); --! inputs from threshold comparators
reset_i : IN std_logic;
coarse_timestamp_i : in std_logic_vector (g_NUM_COARSE_TS_BITS-1 DOWNTO 0); --! Global timestamp. Clocked on clk_4x_logic, but only increments with logic_strobe
trigger_times_o : OUT t_triggerTimeArray (g_NUM_INPUTS-1 DOWNTO 0); --! trigger arrival time ( w.r.t. logic_strobe)
trigger_o : OUT std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0); --! Goes high on leading edge of trigger, in sync with clk_4x_logic_i
--trigger_debug_o : OUT std_logic_vector ( ((2*g_NUM_INPUTS)-1) DOWNTO 0); --! Copy of input trigger level. High bits CFD, Low threshold
......@@ -127,13 +131,13 @@ ARCHITECTURE rtl OF triggerInputs_newTLU IS
signal s_edge_falling_times: t_triggerTimeArray (g_NUM_INPUTS-1 DOWNTO 0); --! edge arrival time ( w.r.t. logic_strobe)
signal s_edge_rising: std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0); --! High when rising edge
signal s_edge_falling: std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0); --! High when falling edge
constant c_N_CTRL : positive := 1;
constant c_N_CTRL : positive := 2;
constant c_N_STAT : positive := g_NUM_INPUTS+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);
-- signal s_reset_reg , s_status_reg: std_logic_vector(g_IPBUS_WIDTH-1 downto 0) := (others => '0');
signal s_counter_reset, s_calibrate_idelay: std_logic := '0';
signal s_select_input_invert : std_logic_vector(g_NUM_INPUTS-1 downto 0) := ( others => '1'); -- set bit high to invert input
BEGIN
-----------------------------------------------------------------------------
-- IPBus interface
......@@ -143,6 +147,7 @@ BEGIN
-- by synchronizer.
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,
......@@ -179,7 +184,8 @@ BEGIN
s_rst_iserdes <= reset_i or s_sync_control_from_ipbus(0)(0);
s_counter_reset <= s_sync_control_from_ipbus(0)(1);
s_calibrate_idelay <= s_sync_control_from_ipbus(0)(2);
s_select_input_invert <= s_sync_control_from_ipbus(1)(g_NUM_INPUTS-1 downto 0);
s_status_to_ipbus(0)(0) <= s_rst_iserdes;
s_status_to_ipbus(0)(1) <= s_counter_reset;
s_status_to_ipbus(0)(2) <= s_calibrate_idelay;
......@@ -199,7 +205,11 @@ BEGIN
--BEGIN FOR LOOP
-- Instantiate one for each trigger input of the TLU
trigger_input_loop: for triggerInput in 0 to (g_NUM_INPUTS-1) generate
signal s_edge_rising_time_short : std_logic_vector( (c_NUM_TIME_BITS-c_TRIGIN_NUM_COARSE_TS_BITS)-1 downto 0);
signal s_edge_falling_time_short : std_logic_vector( (c_NUM_TIME_BITS-c_TRIGIN_NUM_COARSE_TS_BITS)-1 downto 0);
begin
-- Differential buffer. Receives differential trigger input and produces a buffered differential signal.
IBUFDS_DIFF_OUT_inst : IBUFDS_DIFF_OUT
generic map (
......@@ -238,25 +248,13 @@ BEGIN
clk_4x_logic_i => clk_4x_logic,
strobe_4x_logic_i => strobe_4x_logic_i,
deserialized_data_i => s_deserialized_threshold_data_l(triggerInput),
first_rising_edge_time_o => s_edge_rising_times(triggerInput),
last_falling_edge_time_o => s_edge_falling_times(triggerInput),
first_rising_edge_time_o => s_edge_rising_time_short,
last_falling_edge_time_o => s_edge_falling_time_short,
rising_edge_o => s_edge_rising(triggerInput),
falling_edge_o => s_edge_falling(triggerInput),
multiple_edges_o => open
);
-- The leading edge may be a high-->low or a low-->high transition (
-- depending on polarity of input signal. ). For now assume that leading
-- edge is low-->high and connect trigger times and trigger output accordingly.
-- In the future have this selectable.
edge_rising_times_o(triggerInput) <= s_edge_rising_times(triggerInput);
edge_falling_times_o(triggerInput) <= s_edge_falling_times(triggerInput);
edge_rising_o(triggerInput) <= s_edge_rising(triggerInput);
edge_falling_o(triggerInput) <= s_edge_falling(triggerInput);
trigger_times_o(triggerInput) <= s_edge_rising_times(triggerInput);
trigger_o(triggerInput) <= s_edge_rising(triggerInput);
p_register_delayed_bits : process ( clk_4x_logic )
begin
if rising_edge(clk_4x_logic) then
......@@ -269,7 +267,50 @@ BEGIN
--s_status_to_ipbus(0)(24+triggerInput) <= s_CFD_previous_late_bit(triggerInput);
end if ;
end process;
s_edge_rising_times(triggerInput) <= coarse_timestamp_i & s_edge_rising_time_short;
s_edge_falling_times(triggerInput) <= coarse_timestamp_i & s_edge_falling_time_short;
-- purpose: registers output of arrivalTimeLUT and performs optional
-- edge inversion
proc_registerLUT_output : process (clk_4x_logic) is
begin -- process proc_registerLUT_output
if rising_edge(clk_4x_logic) then
-- The leading edge may be a high-->low or a low-->high transition (
-- depending on polarity of input signal. ). For now assume that leading
-- edge is low-->high and connect trigger times and trigger output accordingly.
-- In the future have this selectable.
edge_rising_o(triggerInput) <= s_edge_rising(triggerInput);
if (s_edge_rising(triggerInput) = '1') then
edge_rising_times_o(triggerInput) <= s_edge_rising_times(triggerInput);
end if;
edge_falling_o(triggerInput) <= s_edge_falling(triggerInput);
if (s_edge_falling(triggerInput) = '1') then
edge_falling_times_o(triggerInput) <= s_edge_falling_times(triggerInput);
end if;
-- If s_select_input_invert(triggerInput) = 0 then connect up
-- rising edge. Otherwise falling edge.
if s_select_input_invert(triggerInput) = '0' then
trigger_o(triggerInput) <= s_edge_rising(triggerInput);
if (s_edge_rising(triggerInput) = '1') then
trigger_times_o(triggerInput) <= s_edge_rising_times(triggerInput);
end if;
else
trigger_o(triggerInput) <= s_edge_falling(triggerInput);
if (s_edge_falling(triggerInput) = '1') then
trigger_times_o(triggerInput) <= s_edge_falling_times(triggerInput);
end if;
end if;
end if;
end process proc_registerLUT_output;
--! Instantiate counter for output triggers.
--! Input I is connected to address I+1
cmp_inputTriggerCounter : entity work.counterWithReset
......
Simulation of trigger inputs
ipbb proj create sim triggerInputs_sim fmc-mtlu-gw:AIDA_tlu/components/tlu/sim -t ../../cfg/triggerInputs_newTLU_tb.dep
cd proj/triggerInputs_sim
ipbb sim setup-simlib ipcores fli
ipbb sim make-project
./vsim
Point to input and output files on command line:
vsim -voptargs=+acc work.triggerinputs_newtlu_tb(bench) -G g_BFMINPUT="/users/phdgc/tlu-tmp-2020-2-24/work/build/proj/triggerInputs_sim/BFM_INPUT_01.txt" -G g_BFMOUTPUT="/users/phdgc/tlu-tmp-2020-2-24/work/build/proj/triggerInputs_sim/BFM_OUTPUT_01.txt"
... or just
vsim work.triggerinputs_newtlu_tb -G g_BFMINPUT=BFM_INPUT_01.txt -G g_BFMOUTPUT=BFM_OUTPUT_01.txt
./vsim -c work.triggerinputs_newtlu_tb -G g_BFMINPUT=BFM_INPUT_02.txt -G g_BFMOUTPUT=BFM_OUTPUT_02.txt -do "run -all"
Reads from input file
cmd arg1 arg2 ....
cmd =
0 IPBUS
1 RESET
2 PAUSE
3 PULSE
pulse args...
3 delay0 width0 delay1 width1 delay2 width2 delay3 width3 delay4 width4 delay5 width5
IPBus args
0 w/r/rc addr data
w/r/rc = 0 : write , 1: read , 2: read with check
Pause args ...
2 nclock_cycles
@device_family = "artix7"
@device_name = "xc7a35t"
@device_package = "csg324"
@device_speed = "-2"
@boardname = "enclustra_ax3_pm3"
src --vhdl2008 -c AIDA_tlu/components/tlu ../../sim/hdl/triggerInputs_newTLU_tb.vhd
src --vhdl2008 -c AIDA_tlu/components/tlu ../../sim/hdl/transactionGenerator_behavioural.vhd
src --vhdl2008 -c AIDA_tlu/components/tlu ../../sim/hdl/ipbusTransactor_behavioural.vhd
src -c AIDA_tlu/components/tlu ../../sim/hdl/variablePulseTransactor_rtl.vhd
src -c AIDA_tlu/components/tlu ../../sim/hdl/BFMTypes.vhd
src -c AIDA_tlu/components/tlu trigger/triggerInputs_newTLU_rtl.vhd
src -c ipbus-firmware:components/ipbus_slaves ipbus_ctrlreg_v.vhd
src -c ipbus-firmware:components/ipbus_slaves ipbus_syncreg_v.vhd
src -c ipbus-firmware:components/ipbus_slaves syncreg_w.vhd
src -c ipbus-firmware:components/ipbus_slaves syncreg_r.vhd
src -c ipbus-firmware:components/ipbus_core ipbus_fabric_sel.vhd
src -c AIDA_tlu/components/tlu synchronizeRegisters_rtl.vhd
src -c AIDA_tlu/components/tlu trigger/arrivalTimeLUT_rtl.vhd
src --vhdl2008 -c AIDA_tlu/components/tlu trigger/dualSERDES_1to4_rtl.vhd
src -c AIDA_tlu/components/tlu trigger/IODELAYCal_FSM_rtl.vhd
src -c AIDA_tlu/components/tlu counterWithReset_rtl.vhd
src -c AIDA_tlu/components/tlu logic_clocks_rtl.vhd
src -c ipbus-firmware:components/ipbus_slaves ipbus_reg_types.vhd
src -c ipbus-firmware:components/ipbus_core ipbus_package.vhd
# Include type definitions for TLU
src -c AIDA_tlu/components/tlu fmcTLU_pkg_body.vhd
src -c AIDA_tlu/components/tlu fmcTLU_pkg.vhd
-- Package File Template
--
-- Purpose: This package defines supplemental types, subtypes,
-- constants, and functions
-- Defines types used for "Bus Functional Model" of pulse generation and
-- IPBus cycle generation
library IEEE;
use IEEE.STD_LOGIC_1164.all;
USE ieee.numeric_std.ALL;
package BFMTypes is
constant c_BUSWIDTH : natural := 32;
-- List transaction types
constant NTRANSACTION_TYPES : integer := 4;
constant IPBUS : integer := 0;
constant RESET : integer := 1;
constant PAUSE : integer := 2;
constant PULSE : integer := 3;
constant COMMENT : integer := 777; -- make it large and easy to remember
constant WRITE_TO_SLAVE : integer := 0;
constant READ_FROM_SLAVE : integer := 1;
constant READ_FROM_SLAVE_WITH_CHECK : integer := 2;
-- map each transaction onto a port with a transactor attached
constant NTRANSACTORS : integer := 2;
constant IPBUSPORT : integer := 0;
constant PULSEPORT : integer := 1;
type t_transactorMap is array (NTRANSACTION_TYPES - 1 downto 0) of integer;
constant c_transactorMap : t_transactorMap := (IPBUS => IPBUSPORT,
RESET => 999,
PAUSE => 999,
PULSE => PULSEPORT
);
type t_transactorReturnValues is array (NTRANSACTORS - 1 downto 0) of integer;
constant TIMEUNIT : time := 100 ps; --! Sets units for pulse and sync
subtype t_wbTransactionReturn is std_logic_vector(c_BUSWIDTH - 1 downto 0);
type t_wbTransaction is record
r_read_write : integer;
r_addr : t_wbTransactionReturn;
r_data : t_wbTransactionReturn;
end record;
constant c_wbNullTransactionReturn : t_wbTransactionReturn := (others => '0');
-- Define the number of channels with pulses on....
constant c_NPULSE_CHANNELS : integer := 6;
type t_PULSEDEF is record
r_delay : integer;
r_width : integer;
end record;
type t_pulseTransaction is array (c_NPULSE_CHANNELS - 1 downto 0) of t_PULSEDEF;
subtype t_pulseTransactionReturn is integer;
-- VHDL 2008 has no dynamically sizable strings :-(
constant c_MAX_COMMAND_LINE_LENGTH : integer := (25 * c_NPULSE_CHANNELS) + 200;
end BFMTypes;
--! @file
--
---------------------------------------------------------------------------------------------------
--! @brief Simulation of a IPBus master ( subset of Wishbone master ) --
---------------------------------------------------------------------------------------------------
--
-- unit name: testbench (main_tb.vhd)
--
-- @author David Cussans
--
--! @details
--! based on code by Miguel Mendez (mmendez@sevensols.com),
--! http://svn.ohwr.org/qdr2-v6-core/trunk/hdl/sim/main_tb.vhd
--
-- @date 29-2-2012
--
-- version: 0.1
--
-- dependencies:
--
---------------------------------------------------------------------------------------------------
-- last changes: see svn log.
---------------------------------------------------------------------------------------------------
-- TODO: - .
---------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------
-- GNU LESSER GENERAL PUBLIC LICENSE |
-- ------------------------------------ |
-- This source file is free software; you can redistribute it and/or modify it under the terms of |
-- the GNU Lesser General Public License as published by the Free Software Foundation; either |
-- version 2.1 of the License, or (at your option) any later version. |
-- This source is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; |
-- without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
-- See the GNU Lesser General Public License for more details. |
-- You should have received a copy of the GNU Lesser General Public License along with this |
-- source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html |
---------------------------------------------------------------------------------------------------
--=================================================================================================
-- Libraries & Packages
--=================================================================================================
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
use STD.TEXTIO.all;
--! Declaration of transaction types for Bus Functional Model
use work.BFMTypes.all;
use work.ipbus.all; --! Declarations of IPBus records
entity ipbusTransactor is
port (
-- interface to transaction generator
Trans : in t_wbTransaction; --! Transaction from transaction generator
returnedData : out t_wbTransactionReturn; --! Signal end-of-cycle by making a transaction on this port
-- interface to "physical" ports
clk_i : in std_logic; --! System clock, active high
ipb_to_slave : out ipb_wbus; --! Signals from master to slave
ipb_from_slave : in ipb_rbus --! Signals from slave to master
);
end ipbusTransactor;
architecture behavioural of ipbusTransactor is
begin -- behavioural
p_commandloop: process
variable v_addr : integer;
variable v_addr_ack : integer;
variable outline : line;
variable v_data_from_slave : t_wbTransactionReturn := ( others => '0'); --! Temporary store for data
--read from slave.
variable v_receivedAck : boolean := false; -- set true when strobe goes high...
begin -- process p_commandloop
-- set the bus idle
ipb_to_slave.ipb_strobe <= '0';
ipb_to_slave.ipb_write <= '0';
ipb_to_slave.ipb_addr <= ( others => '1'); --! Set to a dummy value....
wait on Trans'TRANSACTION;
report "wishboneMasterBFM: Got transaction" severity note;
ipb_to_slave.ipb_strobe <= '1';
if( Trans.r_read_write = WRITE_TO_SLAVE ) then
-- Write data
ipb_to_slave.ipb_write <= '1';
ipb_to_slave.ipb_wdata <= Trans.r_data;
else
-- Read data
ipb_to_slave.ipb_write <= '0';
end if;
-- Addr for writing and reading
ipb_to_slave.ipb_addr <= Trans.r_addr;
v_receivedAck := false;
-- Loop until the slave raises ack.
while v_receivedAck = false loop
wait until rising_edge(clk_i); -- s_wb_clk'event and s_wb_clk = '1';
--got ack?
if(ipb_from_slave.ipb_ack = '1') then
v_receivedAck := true;
--read data
if(Trans.r_read_write=READ_FROM_SLAVE) or (Trans.r_read_write=READ_FROM_SLAVE_WITH_CHECK) then
-- the read data is stored
v_data_from_slave := ipb_from_slave.ipb_rdata;
report "Read from slave. Data = " & to_hstring(v_data_from_slave) severity note;
else -- if a write then ....
v_data_from_slave := Trans.r_data; -- just return what we were given
end if;
end if;
end loop;
-- terminate the cycle
ipb_to_slave.ipb_strobe <= '0';
ipb_to_slave.ipb_write <= '0';
report "returning data = " & to_hstring(v_data_from_slave) severity note;
returnedData <= v_data_from_slave; -- This event is what signals the end
-- of transaction.
end process p_commandloop;
end behavioural;
--=============================================================================
--! @file wishboneTransactionGenerator_behavioural.vhd
--=============================================================================
--! Standard library
library IEEE;
--! Standard packages
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
--! Package containg type definition and constants
use work.BFMTypes.all;
use std.TEXTIO.all;
-------------------------------------------------------------------------------
-- --
-- University of Bristol, High Energy Physics Group.
-- --
-------------------------------------------------------------------------------
-- unit name: wishboneTransactionGenerator
--
--! @brief Loops Generating transactions to send to BFM
--
--! @author David Cussans , David.Cussans@bristol.ac.uk
--
--! @date 2\1\2012
--
--! @version v0.1
--
--! @details
--! Must be compiled with VHDL-2008 ( uses HREAD and HWRITE ).
--! \li Pause = 2 [delay]
--! \li Pulse (delay,width in 100ps ticks) = 3 [delay before pulse] [width]
--! \li IPBus transaction = 0 [ipbus params]
--! \li IPBus write = 0 0 [addr] [data]
--! \li IPBus read = 0 1 [addr] [dummy]
--! <b>Dependencies:</b>\n
--! None
--!
--! <b>References:</b>\n
--! referenced by ipbusMarocADC_tb \n
--!
--! <b>Modified by:</b>\n
--! Author:
-------------------------------------------------------------------------------
--! \n\n<b>Last changes:</b>\n
--! 9/March/2012 DGC - changing address and data to be STD_LOGIC_VECTOR. \n
--! using HWRITE / HREAD for Hexidecimal IO
--! 1/March/2020 DGC - repurposed for AIDA-2020 TLU work. Changed syntax
-------------------------------------------------------------------------------
--! @todo <next thing to do> \n
--! <another thing to do> \n
--
--------------------------------------------------------------------------------
entity wishboneTransactionGenerator is
generic (
g_BUSWIDTH : integer := c_BUSWIDTH; --! Number of bits in each word
BFMINPUT : string := "$BFMINPUT"; --! File containing list of commands
BFMOUTPUT : string := "$BFMOUTPUT" --! Output file
);
port (
wb_transaction_o : out t_wbTransaction; -- ! signal that carries transaction to
-- IPBus interface
wb_returned_data_i : in t_wbTransactionReturn; -- ! Carrys data back from BFM
pulse_transaction_o : out t_pulseTransaction;
pulse_returned_data_i : in t_pulseTransactionReturn;
--! Signal to clock generator
endOfSim_o : out boolean --! Take high to stop simulation.
);
end wishboneTransactionGenerator;
architecture behavioural of wishboneTransactionGenerator is
signal s_command_time : time; -- Store the time the commands are issued.
begin -- behavioural
p_commandLoop : process
file COMMANDS : text;
file DATA : text;
variable status : file_open_status;
variable Lin : line;
variable Lout : line;
-- variable debugL : line;
variable v_comment : string(1 to c_MAX_COMMAND_LINE_LENGTH);
variable v_wb_returned_data : t_wbTransactionReturn;
variable v_currentWbTransaction : t_wbTransaction;
variable v_pulse_returned_data : t_pulseTransactionReturn;
variable v_currentPulseTransaction : t_pulseTransaction;
variable textLine : line;
variable v_transactor_id : integer := 999; --! Halt with error if
--transactor ID not set...
variable v_transactionType : integer := 999;
variable v_pauseValue : integer;
--variable v_wb_returned_data : t_wbTransactionReturn ;
begin
-- open input and output files
FILE_OPEN(status, COMMANDS, BFMINPUT, read_mode);
FILE_OPEN(status, DATA, BFMOUTPUT, write_mode);
endOfSim_o <= false;
while not ENDFILE(COMMANDS) loop --! Loop over commands from BFMINPUT
s_command_time <= NOW;
READLINE(COMMANDS, Lin);
READ(Lin, v_transactionType); --! Read the transaction type as the first item on line
if (v_transactionType = PULSE) then
for pulseChan in 0 to c_NPULSE_CHANNELS-1 loop
READ(Lin, v_currentPulseTransaction(pulseChan).r_delay);
READ(Lin, v_currentPulseTransaction(pulseChan).r_width);
end loop; -- pulseChan
pulse_transaction_o <= v_currentPulseTransaction;
wait on pulse_returned_data_i'transaction; -- read the data returned by BFM
v_pulse_returned_data := pulse_returned_data_i;
-- bodge up a return printout
WRITE(Lout, v_pulse_returned_data, left, 20);
elsif (v_transactionType = COMMENT) then
-- read in comment string..
assert Lin'length < v_comment'length; -- make sure S is big enough
v_comment := (others => ' '); -- make sure that the previous line is overwritten
if Lin'length > 0 then
read(Lin, v_comment(1 to Lin'length));
end if;
-- we have a comment
WRITE(Lout, v_comment, left, v_comment'length);
elsif (v_transactionType = IPBUS) then
-- we have an IPBus transaction
-- Read line of form
-- r/w addr data
READ(Lin, v_currentWbTransaction.r_read_write);
HREAD(Lin, v_currentWbTransaction.r_addr);
HREAD(Lin, v_currentWbTransaction.r_data); -- Need to provide dummy data for reads.
-- Issue transaction to Wishbone (IPBus) port
wb_transaction_o <= v_currentWbTransaction;
wait on wb_returned_data_i'transaction; -- read the data returned by BFM
v_wb_returned_data := wb_returned_data_i;
write(LOut,
"transaction type, addr, data, returned data, current time: " &
to_hstring(to_unsigned(v_currentWbTransaction.r_read_write, 32)) & string'(" ") &
to_hstring(unsigned(v_currentWbTransaction.r_addr)) & string'(" ") &
to_hstring(unsigned(v_currentWbTransaction.r_data)) & string'(" ") &
to_hstring(unsigned(v_wb_returned_data)) & string'(" ") &
time'image(s_command_time)
);
elsif (v_transactionType = PAUSE) then
-- Read number of time ticks ( 100ps ) to pause for
READ(Lin, v_pauseValue);
report "BFM: Pausing for clock cycles = " & to_string(v_pauseValue) & " starting at " & time'image(s_command_time) severity note;
wait for v_pauseValue * TIMEUNIT;
else
report "BFM: Bad command type. Exiting" severity error;
end if;
WRITELINE(DATA, Lout);
--! Flush the buffers every time we write a line....
FLUSH(DATA);
end loop; -- idx
report "Ending simulation" severity note;
endOfSim_o <= true;
wait;
end process p_commandLoop;
end behavioural;
library IEEE;
use IEEE.Std_logic_1164.all;
use IEEE.Numeric_Std.all;
use work.ipbus.all;
use work.ipbus_reg_types.all;
use work.fmcTLU.all;
use work.BFMTypes.all;
entity triggerInputs_newTLU_tb is
generic (
g_NUM_INPUTS : natural := 6;
g_IPBUS_WIDTH : positive := 32;
g_BFMINPUT : string := "$BFMINPUT";
g_BFMOUTPUT : string := "$BFMOUTPUT"
);
end;
architecture bench of triggerInputs_newTLU_tb is
component triggerInputs_newTLU
generic(
g_NUM_INPUTS : natural := g_NUM_INPUTS;
g_NUM_COARSE_TS_BITS : natural := 3; --! Number of coarse ( clk_1x_logic normally 40MHz ) timestamp bits to add to MSB of trigger times.
g_IPBUS_WIDTH : positive := g_IPBUS_WIDTH
);
port(
clk_4x_logic : in std_logic;
clk_200_i : in std_logic;
strobe_4x_logic_i : in std_logic;
threshold_discr_p_i : in std_logic_vector (g_NUM_INPUTS-1 downto 0);
threshold_discr_n_i : in std_logic_vector (g_NUM_INPUTS-1 downto 0);
reset_i : in std_logic;
coarse_timestamp_i : in std_logic_vector (g_NUM_COARSE_TS_BITS-1 DOWNTO 0); --! Global timestamp. Clocked on clk_4x_logic, but only increments with logic_strobe
trigger_times_o : out t_triggerTimeArray (g_NUM_INPUTS-1 downto 0);
trigger_o : out std_logic_vector (g_NUM_INPUTS-1 downto 0);
edge_rising_times_o : out t_triggerTimeArray (g_NUM_INPUTS-1 downto 0);
edge_falling_times_o : out t_triggerTimeArray (g_NUM_INPUTS-1 downto 0);
edge_rising_o : out std_logic_vector (g_NUM_INPUTS-1 downto 0);
edge_falling_o : out std_logic_vector (g_NUM_INPUTS-1 downto 0);
ipbus_clk_i : in std_logic;
ipbus_reset_i : in std_logic;
ipbus_i : in ipb_wbus;
ipbus_o : out ipb_rbus;
clk_8x_logic_i : in std_logic;
strobe_8x_logic_i : in std_logic
);
end component;
signal clk_4x_logic : std_logic := '0';
signal clk_200_i : std_logic;
signal strobe_4x_logic_i : std_logic;
signal s_pulses : std_logic_vector (g_NUM_INPUTS-1 downto 0);
signal threshold_discr_p_i : std_logic_vector (g_NUM_INPUTS-1 downto 0);
signal threshold_discr_n_i : std_logic_vector (g_NUM_INPUTS-1 downto 0);
signal reset_i : std_logic;
signal trigger_times_o : t_triggerTimeArray (g_NUM_INPUTS-1 downto 0);
signal trigger_o : std_logic_vector (g_NUM_INPUTS-1 downto 0);
signal edge_rising_times_o : t_triggerTimeArray (g_NUM_INPUTS-1 downto 0);
signal edge_falling_times_o : t_triggerTimeArray (g_NUM_INPUTS-1 downto 0);
signal edge_rising_o : std_logic_vector (g_NUM_INPUTS-1 downto 0);
signal edge_falling_o : std_logic_vector (g_NUM_INPUTS-1 downto 0);
signal ipbus_clk_i : std_logic;
signal ipbus_reset_i : std_logic;
signal ipbus_i : ipb_wbus;
signal ipbus_o : ipb_rbus;
signal clk_8x_logic_i : std_logic;
signal clk_logic : std_logic;
signal strobe_8x_logic_i : std_logic;
signal s_coarse_timestamp : std_logic_vector(c_TRIGIN_NUM_COARSE_TS_BITS-1 downto 0) := ( others => '0' ); -- counts on each strobe_4x_logic pulse
-- constant C_NUM_STROBE_TAPS : positive := 2; --! Adjust to shift strobes relative to 40MHz clock edge
-- signal s_clk40_delayed_160 : std_logic_vector(C_NUM_STROBE_TAPS downto 0); --! Shift register used to generate clock_4x strobe. Adjust length for correct alignment with incoming clock
-- signal s_clk40_delayed_320 : std_logic_vector((2*C_NUM_STROBE_TAPS)+1 downto 0); --! Shift register used to generate clock_8x strobe. Adjust length for correct alignment with incoming clock
signal s_dut_clk, s_clocks_locked, s_logic_reset : std_logic;
signal s_pulseTransaction : t_pulseTransaction;
signal s_pulseTransactionReturn : t_pulseTransactionReturn;
signal s_wbTransaction : t_wbTransaction;
signal s_wbTransactionReturn : t_wbTransactionReturn;
signal s_pulse_sync : std_logic := '0'; -- strobe high once every 8 clock cycles of 40MHz
signal s_triggerNumber : std_logic_vector(g_IPBUS_WIDTH - 1 downto 0);
constant delta : time := 0.02 ns; -- make sure IPBus clock drifts w.r.t.
-- logic clocks
constant clockLogic_period : time := 25 ns; -- 40MHz clock
--constant clock320_period: time := 3.125 ns; -- 320 MHz clock
constant clock200_period : time := 5 ns + delta; -- 200 MHz clock
constant clockipbus_period : time := 31.25 ns + delta; -- 320 MHz clock
signal stop_the_clock : boolean := false;
-- Look at /projects/HEP_Instrumentation/cad/designs/uob-hep-pc043a/trunk/firmware/maroc3_fmc/sim_src/variablePulseTransactor_rtl.vhd
--/projects/HEP_Instrumentation/cad/designs/uob-hep-pc043a/trunk/firmware/maroc3_fmc/sim_src/wishbone_master_behavioural.vhd
-- and friends for parameterizable pulse generator.
begin
-- Insert values for generic parameters !!
uut : triggerInputs_newTLU generic map (g_NUM_INPUTS => g_NUM_INPUTS,
g_IPBUS_WIDTH => g_IPBUS_WIDTH)
port map (clk_4x_logic => clk_4x_logic,
clk_200_i => clk_200_i,
strobe_4x_logic_i => strobe_4x_logic_i,
threshold_discr_p_i => threshold_discr_p_i,
threshold_discr_n_i => threshold_discr_n_i,
reset_i => s_logic_reset,
coarse_timestamp_i => s_coarse_timestamp,
trigger_times_o => trigger_times_o,
trigger_o => trigger_o,
edge_rising_times_o => edge_rising_times_o,
edge_falling_times_o => edge_falling_times_o,
edge_rising_o => edge_rising_o,
edge_falling_o => edge_falling_o,
ipbus_clk_i => ipbus_clk_i,
ipbus_reset_i => ipbus_reset_i,
ipbus_i => ipbus_i,
ipbus_o => ipbus_o,
clk_8x_logic_i => clk_8x_logic_i,
strobe_8x_logic_i => strobe_8x_logic_i);
proc_PrintTimes: process (trigger_o) is
begin -- process proc_PrintTimes
if rising_edge(trigger_o(0)) or rising_edge(trigger_o(1)) then
report "Got a trigger time " & to_hstring(s_triggerNumber) & " " & time'image(NOW) & " " & to_hstring(trigger_times_o(0)) & " " & to_hstring(trigger_times_o(1)) & " "& to_hstring(trigger_times_o(2)) & " "& to_hstring(trigger_times_o(3)) & " "& to_hstring(trigger_times_o(4)) & " "& to_hstring(trigger_times_o(5)) severity note;
end if;
end process proc_PrintTimes;
stimSequence : process
begin
-- Put initialisation code here
reset_i <= '1';
ipbus_reset_i <= '1';
wait for clockLogic_period * 16;
reset_i <= '0';
ipbus_reset_i <= '0';
-- Wait for commands to be played through
wait until stop_the_clock;
reset_i <= '1';
wait;
end process;
transactionGen : entity work.wishboneTransactionGenerator
generic map (
g_BUSWIDTH => g_IPBUS_WIDTH, --! Number of bits in each word
BFMINPUT => g_BFMINPUT , --! File containing list of commands
BFMOUTPUT => g_BFMOUTPUT --! Output file
)
port map (
wb_transaction_o => s_wbTransaction, -- ! signal that carries transaction to IPBus transactor
wb_returned_data_i => s_wbTransactionReturn, -- ! Carrys data back from BFM
pulse_transaction_o => s_pulseTransaction,
pulse_returned_data_i => s_pulseTransactionReturn,
--! Signal to clock generator
endOfSim_o => stop_the_clock --! Take high to stop simulation.
);
s_pulse_sync <= '1' when strobe_4x_logic_i='1' and s_coarse_timestamp = "000" and rising_edge(strobe_4x_logic_i) else '0';
pulseGen: entity work.variablePulseTransactor
generic map (
g_BUSWIDTH => g_IPBUS_WIDTH) -- width for triggernumber and timestamp
port map (
--clk_i => strobe_4x_logic_i,
clk_i => s_pulse_sync,
trans_i => s_pulseTransaction,
returnedData_o => s_pulseTransactionReturn,
signal_o => s_pulses,
triggerNumber_o => s_triggerNumber,
timeStamp_o => open
);
threshold_discr_p_i <= s_pulses;
threshold_discr_n_i <= not s_pulses;
ipbusGen : entity work.ipbusTransactor
port map (
-- interface to transaction generator
Trans => s_wbTransaction,
returnedData => s_wbTransactionReturn,
-- interface to "physical" ports
clk_i => ipbus_clk_i,
ipb_to_slave => ipbus_i, --! Signals from master to slave
ipb_from_slave => ipbus_o --! Signals from slave to master
);
clockGenerator : entity work.logic_clocks
port map (
ipbus_clk_i => ipbus_clk_i,
ipbus_i => ipbus_i,
ipbus_reset_i => ipbus_reset_i,
Reset_i => reset_i,
clk_logic_xtal_i => clk_logic,
clk_8x_logic_o => clk_8x_logic_i,
clk_4x_logic_o => clk_4x_logic,
ipbus_o => ipbus_o,
strobe_8x_logic_o => strobe_8x_logic_i,
strobe_4x_logic_o => strobe_4x_logic_i,
DUT_clk_o => s_dut_clk,
logic_clocks_locked_o => s_clocks_locked,
logic_reset_o => s_logic_reset
);
clockLogic : process
begin
while not stop_the_clock loop
clk_logic <= '0', '1' after clockLogic_period / 2;
wait for clockLogic_period;
end loop;
wait;
end process;
clockIpbus : process
begin
while not stop_the_clock loop
ipbus_clk_i <= '0', '1' after clockipbus_period / 2;
wait for clockipbus_period;
end loop;
wait;
end process;
clock200 : process
begin
while not stop_the_clock loop
clk_200_i <= '0', '1' after clock200_period / 2;
wait for clock200_period;
end loop;
wait;
end process;
tsCounter : process
variable v_tsctr : unsigned ( c_TRIGIN_NUM_COARSE_TS_BITS-1 downto 0) := (others => '0') ;
begin
while not stop_the_clock loop
wait until rising_edge(clk_4x_logic);
if reset_i = '1' then
v_tsctr := ( others => '0');
elsif strobe_4x_logic_i ='1' then
v_tsctr := v_tsctr + 1;
end if;
s_coarse_timestamp <= std_logic_vector(v_tsctr);
end loop;
wait;
end process;
end;
--! @file
--!
--! @brief Issues a pulse of variable width and delay. Based on pulseTransactor
--! @author David Cussans
--! @date 23\4\2013
--
--! Note - have to compile with VHDL-2008
--
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
use STD.TEXTIO.all;
--! Declaration of transaction types for Bus Functional Model
use work.BFMTypes.all;
use std.TEXTIO.all;
entity variablePulseTransactor is
generic(
g_BUSWIDTH : integer := 32); -- width for triggernumber and timestamp
port(
clk_i : in std_logic;
trans_i : in t_pulseTransaction;
returnedData_o : out t_pulseTransactionReturn;
signal_o : out std_logic_vector(c_NPULSE_CHANNELS - 1 downto 0); --! Signal pulses low-high-low
triggerNumber_o : out std_logic_vector(g_BUSWIDTH - 1 downto 0);
timeStamp_o : out std_logic_vector(g_BUSWIDTH - 1 downto 0)
);
end variablePulseTransactor;
architecture rtl of variablePulseTransactor is
signal s_timeStamp : unsigned(g_BUSWIDTH - 1 downto 0) := (others => '0');
constant c_timeGranularity : time := 1 ps;
signal s_pulseNum : integer := 0;
begin -- rtl
p_pulseGen : process is
variable v_pulseDelay : time := 0 ps;
variable v_pulseWidth : time := 0 ps;
variable v_lastEdge : time := 0 ps;
begin
report "variablePulseBFM: waiting for transaction" severity note;
signal_o <= (others => '0');
wait on trans_i'transaction;
report "variablePulseBFM: Got transaction" severity note;
wait until rising_edge(clk_i);
for chan in 0 to signal_o'length - 1 loop
v_pulseDelay := trans_i(chan).r_delay * TIMEUNIT;
v_pulseWidth := trans_i(chan).r_width * TIMEUNIT;
if (v_pulseDelay + v_pulseWidth) > v_lastEdge then
v_lastEdge := (v_pulseDelay + v_pulseWidth);
end if;
if trans_i(chan).r_delay >= 0 then
report "Queing pulse . chan , delay , width " & integer'image(chan) & " " & time'image(v_pulseDelay) & " " & time'image(v_pulseWidth);
signal_o(chan) <= '1' after v_pulseDelay, '0' after (v_pulseDelay + v_pulseWidth);
else
report "NO Pulse queued chr chan " & integer'image(chan);
end if;
end loop;
report "Waiting until last edge finished. Delay = " & time'image(v_lastEdge) severity note;
wait for v_lastEdge;
-- Update trigger number
s_pulseNum <= s_pulseNum + 1;
triggerNumber_o <= std_logic_vector(to_unsigned(s_pulseNum, g_BUSWIDTH));
-- output current time-stamp
timeStamp_o <= std_logic_vector(s_timeStamp);
returnedData_o <= s_pulseNum;
end process p_pulseGen;
-- purpose: keeps a timestamp in terms of clock cycles
-- type : sequential
-- inputs : clk_i, s_timeStamp
-- outputs: s_timeStamp
p_timeStamp : process(clk_i)
begin -- process p_timeStamp
if rising_edge(clk_i) then
s_timeStamp <= s_timeStamp + 1;
end if;
end process p_timeStamp;
end rtl;
777 Generate test pulses
2 8000
3 10 1000 100 2000 500 4000 0 200 200 6000 400 8000
2 6000
#!/usr/bin/python
#
# script to generate input for triggerinputs_newtlu_tb
#
print "777 Generate test pulses in 200ps steps"
# waiting for clocks to settle
print "2 8000"
# setting up trigger inputs to look for falling edges
print "0 0 00006001 FFFFFFFF"
#
# generate pulses
for i in range(1000):
print "3 " + str( i * 2) + " 3000 -10 0 -10 0 -10 0 -10 0 -10 0"
# pause between pulses
print "2 3000"
# pause before ending simulation
print "2 8000"
......@@ -50,7 +50,8 @@
</node>
<!-- This needs checking. The counters work, not sure about the reset -->
<node id="triggerInputs" address="0x6000" description="Inputs configuration" fwinfo="endpoint;width=4">
<node id="SerdesRstW" address="0x0" permission="w" description="" />
<node id="SerdesRstW" address="0x0" permission="w" description="" />
<node id="InvertEdgeW" address="0x1" permission="w" description="Set bit high to invert sense of leading edge" />
<node id="SerdesRstR" address="0x8" permission="r" description="" />
<node id="ThrCount0R" address="0x9" permission="r" description="" />
<node id="ThrCount1R" address="0xa" permission="r" description="" />
......
......@@ -51,7 +51,7 @@ use work.ipbus.ALL;
entity top is
generic(
constant FW_VERSION : unsigned(31 downto 0):= X"1e000024"; -- Firmware revision. Remember to change this as needed.
constant FW_VERSION : unsigned(31 downto 0):= X"1e000025"; -- Firmware revision. Remember to change this as needed.
g_NUM_DUTS : positive := 4; -- <- was 3
g_NUM_TRIG_INPUTS :positive := 6;-- <- was 4
g_NUM_EDGE_INPUTS :positive := 6;-- <-- was 4
......@@ -171,6 +171,7 @@ architecture rtl of top is
SIGNAL triggers : std_logic_vector(g_NUM_TRIG_INPUTS-1 DOWNTO 0); --! Rising edge of trigger inputs
SIGNAL s_veto : std_logic; --! goes high when one or more DUT are busy
signal s_shutter_veto : std_logic; --! Goes high when triggers should be vetoed by shutter
signal s_coarse_timestamp : std_logic_vector(c_COARSE_TIMESTAMP_WIDTH-1 downto 0) := (others => '0'); -- 40MHz timestamp.
signal ctrl, stat: ipb_reg_v(0 downto 0);
--My signals
--SIGNAL busy_toggle_o : std_logic_vector(g_NUM_DUTS-1 downto 0);
......@@ -257,6 +258,7 @@ architecture rtl of top is
COMPONENT eventFormatter
GENERIC (
g_EVENT_DATA_WIDTH : positive := 64;
g_COARSE_TIMESTAMP_WIDTH : positive := 48; -- ! Number of bits in 40MHz timestamp
g_IPBUS_WIDTH : positive := 32;
g_COUNTER_TRIG_WIDTH : positive := 32;
g_COUNTER_WIDTH : positive := 12;
......@@ -288,6 +290,7 @@ architecture rtl of top is
ipbus_o : OUT ipb_rbus ;
data_strobe_o : OUT std_logic ; --! goes high when data ready TO load into event buffer
event_data_o : OUT std_logic_vector (g_EVENT_DATA_WIDTH-1 DOWNTO 0);
coarse_timestamp_o : out std_logic_vector (g_COARSE_TIMESTAMP_WIDTH-1 DOWNTO 0); --! Global timestamp. Clocked on clk_4x_logic, but only increments with logic_strobe
reset_timestamp_i : IN std_logic ; --! Taking high causes timestamp TO be reset. Combined with internal timestmap reset and written to reset_timestamp_o
reset_timestamp_o : OUT std_logic --! Goes high for one clock cycle of clk_4x_logic when timestamp reset
);
......@@ -320,7 +323,8 @@ architecture rtl of top is
----------------------------------------------
COMPONENT triggerInputs_newTLU
GENERIC (
g_NUM_INPUTS : natural := 1;
g_NUM_INPUTS : natural := 1;
g_NUM_COARSE_TS_BITS : natural := 3; --! Number of coarse ( clk_1x_logic normally 40MHz ) timestamp bits to add to MSB of trigger times.
g_IPBUS_WIDTH : positive := 32
);
PORT (
......@@ -332,6 +336,7 @@ architecture rtl of top is
threshold_discr_p_i : IN std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0); --! inputs from threshold comparators
threshold_discr_n_i : IN std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0); --! inputs from threshold comparators
reset_i : IN std_logic ;
coarse_timestamp_i : in std_logic_vector (g_NUM_COARSE_TS_BITS-1 DOWNTO 0); --! Global timestamp. Clocked on clk_4x_logic, but only increments with logic_strobe
trigger_times_o : OUT t_triggerTimeArray (g_NUM_INPUTS-1 DOWNTO 0); --! trigger arrival time ( w.r.t. logic_strobe)
trigger_o : OUT std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0); --! Goes high on leading edge of trigger, in sync with clk_4x_logic_i
--trigger_debug_o : OUT std_logic_vector ( ((2*g_NUM_INPUTS)-1) DOWNTO 0); --! Copy of input trigger level. High bits CFD, Low threshold
......@@ -566,6 +571,7 @@ begin
threshold_discr_p_i => threshold_discr_p_i,
threshold_discr_n_i => threshold_discr_n_i,
reset_i => logic_reset,
coarse_timestamp_i => s_coarse_timestamp(c_TRIGIN_NUM_COARSE_TS_BITS-1 downto 0),
trigger_times_o => trigger_times,
trigger_o => triggers,
--trigger_debug_o => OPEN,
......@@ -616,6 +622,7 @@ begin
ipbus_o => ipbrr(N_SLV_EVENT_FORMATTER),
data_strobe_o => data_strobe,
event_data_o => event_data,
coarse_timestamp_o => s_coarse_timestamp,
reset_timestamp_i => s_T0,
reset_timestamp_o => OPEN
);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment