Commit 14eb481d authored by David Cussans's avatar David Cussans

Checking in changes needed to get firmware to simulate under QuestSim

Also, tidying up code and hopefully reducing potential timing-race and meta-stability
issues.

eventFormatter_rtl.vhd
parent eb9752c5
......@@ -175,13 +175,23 @@ BEGIN
end process examine_lut;
--! Coarse time stamp. Phase w.r.t. strobe
c_coarse_ts : entity work.CounterUp
-- 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 )
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
clock_i => clk_4x_logic_i,
enable_i => '1',
reset_i => strobe_4x_logic_i, --'0',
result_o => s_coarse_bits
);
END ARCHITECTURE rtl;
......
......@@ -36,12 +36,12 @@ architecture rtl of clocks_s6_extphy is
signal s_clk_logic_xtal : std_logic;
-- signal clk_400: std_logic;
component clock_divider_s6 port(
clk: in std_logic;
d25: out std_logic;
d28: out std_logic
);
end component;
-- component clock_divider_s6 port(
-- clk: in std_logic;
-- d25: out std_logic;
-- d28: out std_logic
-- );
-- end component;
begin
......@@ -90,8 +90,10 @@ begin
rst => '0'
);
clkdiv: clock_divider_s6 port map(
clkdiv: entity work.clock_divider_s6 port map(
-- clkdiv: entity work.clock_div port map(
clk => sysclk,
-- D17 => open,
d25 => d25,
d28 => onehz
);
......
--=============================================================================
--! @file counterWithReset_rtl.vhd
--=============================================================================
-------------------------------------------------------------------------------
-- --
-- University of Bristol, High Energy Physics Group.
-- --
------------------------------------------------------------------------------- --
-- unit name: counterWithReset (counterWithReset / rtl)
--
--! @brief Simple counter with synchronous reset
--
--! @author David Cussans , David.Cussans@bristol.ac.uk
--
--! @date Feb\2012
--
--! @version v0.1
--
--! @details
--!
--! <b>Dependencies:</b>\n
--! None
--!
--! <b>References:</b>\n
--! referenced by ipBusMarocTriggerGenerator \n
--!
--! <b>Modified by:</b>\n
--! Author:
-------------------------------------------------------------------------------
--! \n\n<b>Last changes:</b>\n
--! 5/Mar/12 DGC Changed to use numeric_std\n
--! 26/Feb/14 DGC Added registers to output to aid timing closure.
--!
-------------------------------------------------------------------------------
--! @todo <next thing to do> \n
--! <another thing to do> \n
---------------------------------------------------------------------------------
--============================================================================
--! Entity declaration for counterWithReset
--============================================================================
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use ieee.numeric_std.all;
ENTITY counterWithReset IS
GENERIC (g_COUNTER_WIDTH : integer := 32; --! Number of bits
g_OUTPUT_REGISTERS : integer := 4 --! Number of output registers. Minumum =1. Aids timing closure.
);
PORT
(
clock_i: IN STD_LOGIC; --! rising edge active clock
reset_i: IN STD_LOGIC; --! Active high. syncronous with rising clk
enable_i: IN STD_LOGIC; --! counts when enable=1
result_o: OUT STD_LOGIC_VECTOR ( g_COUNTER_WIDTH-1 downto 0) --! Unsigned integer output
);
END counterWithReset;
ARCHITECTURE rtl OF counterWithReset IS
type t_register_array is array(natural range <>) of UNSIGNED ( g_COUNTER_WIDTH-1 downto 0) ; -- --! Array of arrays for output register...
signal s_output_registers : t_register_array(g_OUTPUT_REGISTERS downto 0); -- --! Output registers.
BEGIN
--! Process to count up from zero when enable_i is high.
p_counter: PROCESS (clock_i)
BEGIN
IF rising_edge(clock_i) THEN
IF (reset_i = '1') THEN
s_output_registers(0) <= (others => '0');
ELSIF (enable_i='1') THEN
s_output_registers(0) <= s_output_registers(0) + 1;
END IF;
END IF;
END PROCESS p_counter;
--! Generate some output registers. Number controlled by g_OUTPUT_REGISTERS
generate_registers: for v_register in 1 to g_OUTPUT_REGISTERS generate
--! An individual register
p_outputRegister: process (clock_i)
begin -- process p_outputRegister
if rising_edge(clock_i) then
s_output_registers( v_register) <=
s_output_registers( v_register-1);
end if;
end process p_outputRegister;
end generate generate_registers; -- v_register
--! Copy the (registered) result to the output
result_o <= STD_LOGIC_VECTOR(s_output_registers(g_OUTPUT_REGISTERS));
END rtl;
......@@ -29,6 +29,7 @@
--! Author:
-------------------------------------------------------------------------------
--! \n\n<b>Last changes:</b>\n
--! Separated FSM for calibration control into a separate entity. DGC, 22/Feb/14
-------------------------------------------------------------------------------
--! @todo Implement a periodic calibration sequence\n
--! <another thing to do> \n
......@@ -73,73 +74,20 @@ ARCHITECTURE rtl OF dualSERDES_1to4 IS
signal s_data_o : std_logic_vector(7 downto 0); --! Deserialized data
signal s_rst : std_logic := '0'; -- IODELAY and ISERDES reset
signal s_cal_FSM : std_logic := '0'; --! Take high to calibrate the IDELAY components
signal s_rst_FSM : std_logic := '0'; -- IODELAY reset
signal s_initial_cal : std_logic := '1'; -- Start up calibration flag
signal s_calibration : std_logic := '0'; -- Start calibration
--! Calibration FSM state values
type state_values is (st0, st1, st2, st3, st4);
signal pres_state, next_state: state_values := st0;
BEGIN
--! Calibration start condition
s_calibration <= serdes_reset_i or s_initial_cal;
s_rst <= s_rst_FSM; -- or serdes_reset_i;
--! Calibration FSM register
statereg: process(fabricClk_i, serdes_reset_i)
begin
if rising_edge(fabricClk_i) then
pres_state <= next_state; -- Move to next state
end if;
end process statereg;
--! Calibration FSM combinational block
fsm: process(pres_state, s_calibration, s_busy_idelay_m)
begin
next_state <= pres_state;
-- Default values
s_Rst_FSM <= '0';
s_cal_FSM <= '0';
case pres_state is
-- st0 - IDLE
when st0=>
if ( s_calibration = '1') then
next_state <= st1; -- Next state is "st1 - SEND CALIBRATION SIGNAL"
end if;
-- st1 - SEND CALIBRATION SIGNAL
when st1=>
s_cal_FSM <= '1';
s_initial_cal <= '0';
if s_busy_idelay_m = '1' then
next_state <= st2; -- Next state is "st2 - WAIT BUSY = '0'"
end if;
-- st2 - WAIT BUSY = '0'
when st2=>
if s_busy_idelay_m = '0' then
next_state <= st3; -- Next state is "st3 - RESET STATE"
end if;
-- st3 - RESET STATE
when st3=>
s_Rst_FSM <= '1';
if s_busy_idelay_m = '1' then
next_state <= st4; -- Next state is "st4 - WAIT BUSY = '0'"
end if;
-- st4 - WAIT BUSY = '0'
when st4=>
if s_busy_idelay_m = '0' then
next_state <= st0; -- Next state is "st0 - IDLE"
end if;
end case;
BEGIN
end process fsm;
calibration_fsm: entity work.serdesCalibrateFSM
port map (
fsm_clk_i => fabricClk_i,
serdes_reset_i => serdes_reset_i,
busy_idelay_m_i => s_busy_idelay_m,
calibrate_o => s_cal_FSM,
reset_o => s_rst);
IODELAY2_Prompt : IODELAY2
generic map (
......@@ -147,7 +95,7 @@ BEGIN
DATA_RATE => "SDR", -- "SDR" or "DDR"
DELAY_SRC => "IDATAIN", -- "IO", "ODATAIN" or "IDATAIN"
IDELAY_MODE => "NORMAL", -- "NORMAL" or "PCI"
--SERDES_MODE => "MASTER", -- <NONE>, MASTER, SLAVE
SERDES_MODE => "NONE", -- <NONE>, MASTER, SLAVE
IDELAY_TYPE => "VARIABLE_FROM_HALF_MAX", -- "FIXED", "DEFAULT", "VARIABLE_FROM_ZERO", "VARIABLE_FROM_HALF_MAX"
-- or "DIFF_PHASE_DETECTOR"
IDELAY_VALUE => 0, -- Amount of taps for fixed input delay (0-255)
......@@ -180,8 +128,8 @@ BEGIN
DATA_RATE => "SDR", -- "SDR" or "DDR"
DELAY_SRC => "IDATAIN", -- "IO", "ODATAIN" or "IDATAIN"
IDELAY_MODE => "NORMAL", -- "NORMAL" or "PCI"
--SERDES_MODE => "SLAVE", -- <NONE>, MASTER, SLAVE
IDELAY_TYPE => "FIXED", -- "FIXED", "DEFAULT", "VARIABLE_FROM_ZERO", "VARIABLE_FROM_HALF_MAX"
SERDES_MODE => "NONE", -- <NONE>, MASTER, SLAVE
IDELAY_TYPE => "VARIABLE_FROM_ZERO", -- "FIXED", "DEFAULT", "VARIABLE_FROM_ZERO", "VARIABLE_FROM_HALF_MAX"
-- or "DIFF_PHASE_DETECTOR"
IDELAY_VALUE => 0, -- Amount of taps for fixed input delay (0-255) 10->0.75nS, 11->0.825nS
IDELAY2_VALUE => 0, -- Delay value when IDELAY_MODE="PCI" (0-255)
......@@ -194,12 +142,12 @@ BEGIN
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 => '0', -- 1-bit input: Initiate calibration input
CAL => s_cal_FSM, -- 1-bit input: Initiate calibration input
CE => '0', -- 1-bit input: Enable INC input
CLK => '0', -- 1-bit input: Clock input
IDATAIN => Data_i, -- 1-bit input: Data input (connect to top-level port or I/O buffer)
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 => '0', -- 1-bit input: Input from the I/O clock network
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, -- 1-bit input: reset_i to zero or 1/2 of total delay period
......
......@@ -30,6 +30,8 @@
--! Author:
-------------------------------------------------------------------------------
--! \n\n<b>Last changes:</b>\n
--! 27/Feb/14 DGC Change "If" when setting s_word2 to a case ... generate. Questasim
--! doesn't like having an if that can take an array out of bounds.
-------------------------------------------------------------------------------
--! @todo Add more input data: \n
--! a) shutter signals. One per DUT. ?? \n
......@@ -114,7 +116,7 @@ ARCHITECTURE rtl OF eventFormatter IS
-- 3 - Spill
--! delayed strobes
signal s_event_strobe , s_event_strobe_d1 ,s_event_strobe_d2 ,s_event_strobe_d3 : std_logic := '0';
signal s_event_strobe , s_event_strobe_d1 ,s_event_strobe_d2 ,s_event_strobe_d3 , s_event_strobe_d3_opt : std_logic := '0';
signal shutter_i_d1, shutter_i_d2, edge_i_d1, edge_i_d2, spill_i_d1, spill_i_d2 : std_logic := '0';
signal s_evttype : t_evttype(3+g_NUM_EDGE_INPUTS-1 downto 0) := (others=>(others=>'0')); -- Event type
......@@ -212,9 +214,7 @@ BEGIN
if rising_edge(clk_4x_logic_i) then
s_event_strobe_d1 <= trigger_i and s_enable_trigger;
s_event_strobe_d2 <= s_event_strobe_d1;
if to_unsigned(g_NUM_TRIG_INPUTS,4) > 4 then
s_event_strobe_d3 <= s_event_strobe_d2;
end if;
s_FIFO_rd_d <= s_FIFO_rd;
......@@ -227,6 +227,12 @@ BEGIN
end if;
end process p_reg;
-- If there are more than 4 trigger inputs we need to fill a second word.
-- .. do this by having an optional strobe.
-- If 4 or fewer trigger inputs, just leave s_event_strobe_d3_opt at zero..
gen_strobe_d3: if (g_NUM_TRIG_INPUTS > 4) generate
s_event_strobe_d3_opt <= s_event_strobe_d3;
end generate;
-------------------------------------------------------------------------------
-- Trigger event formater
......@@ -240,40 +246,66 @@ BEGIN
s_word1 <= "000" & trigger_times_i(0) & "000" & trigger_times_i(1) &
"000" & trigger_times_i(2) & "000" & trigger_times_i(3) &
trigger_cnt_i;
s_word2 <= "000" & trigger_times_i(4) & X"00000000000000" when (g_NUM_TRIG_INPUTS = 5) else
"000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
X"000000000000" when (g_NUM_TRIG_INPUTS = 6) else
"000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
"000" & trigger_times_i(6) & X"0000000000" when (g_NUM_TRIG_INPUTS = 7) else
"000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
"000" & trigger_times_i(6) & "000" & trigger_times_i(7) &
X"00000000" when (g_NUM_TRIG_INPUTS = 8) else
"000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
"000" & trigger_times_i(6) & "000" & trigger_times_i(7) &
"000" & trigger_times_i(8) & X"000000" when (g_NUM_TRIG_INPUTS = 9) else
"000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
"000" & trigger_times_i(6) & "000" & trigger_times_i(7) &
"000" & trigger_times_i(8) & "000" & trigger_times_i(9) &
X"0000" when (g_NUM_TRIG_INPUTS = 10) else
"000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
"000" & trigger_times_i(6) & "000" & trigger_times_i(7) &
"000" & trigger_times_i(8) & "000" & trigger_times_i(9) &
"000" & trigger_times_i(10)& X"00" when (g_NUM_TRIG_INPUTS = 11) else
"000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
"000" & trigger_times_i(6) & "000" & trigger_times_i(7) &
"000" & trigger_times_i(8) & "000" & trigger_times_i(9) &
"000" & trigger_times_i(10)& "000" & trigger_times_i(11) when (g_NUM_TRIG_INPUTS = 12) else
(others=>'0');
-- Different number of trigger inputs require packing into s_word2 in
-- different ways.
-- Do this in a generate since g_NUM_TRIG_INPUTS is static and
-- Questasim doesn't like refering to indices outside declared range.
s_word2 <= (others=>'0'); -- Set all bits to zero
-- then override with the following assignments....
gen_word2: for v_trigInput in 4 to g_NUM_TRIG_INPUTS-1 generate
s_word2( (((11-v_trigInput)*8)+c_NUM_TIME_BITS-1) downto ((11-v_trigInput)*8) ) <= trigger_times_i(v_trigInput);
end generate;
-- N.B. This is VHDL-2008 syntax.
-- Would be easier to do this with a for ... generate loop, but I
-- didn't think of this in time....
-- gen_word2: case g_NUM_TRIG_INPUTS generate
-- when 5 =>
-- s_word2 <= "000" & trigger_times_i(4) & X"00000000000000";
-- when 6 =>
-- s_word2 <= "000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
-- X"000000000000";
-- when 7 =>
-- s_word2 <= "000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
-- "000" & trigger_times_i(6) & X"0000000000";
-- when 8 =>
-- s_word2 <= "000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
-- "000" & trigger_times_i(6) & "000" & trigger_times_i(7) &
-- X"00000000";
-- when 9 =>
-- s_word2 <= "000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
-- "000" & trigger_times_i(6) & "000" & trigger_times_i(7) &
-- "000" & trigger_times_i(8) & X"000000" ;
-- when 10 =>
-- s_word2 <= "000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
-- "000" & trigger_times_i(6) & "000" & trigger_times_i(7) &
-- "000" & trigger_times_i(8) & "000" & trigger_times_i(9) &
-- X"0000" ;
-- when 11 =>
-- s_word2 <= "000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
-- "000" & trigger_times_i(6) & "000" & trigger_times_i(7) &
-- "000" & trigger_times_i(8) & "000" & trigger_times_i(9) &
-- "000" & trigger_times_i(10)& X"00" ;
-- when 12 =>
-- s_word2 <= "000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
-- "000" & trigger_times_i(6) & "000" & trigger_times_i(7) &
-- "000" & trigger_times_i(8) & "000" & trigger_times_i(9) &
-- "000" & trigger_times_i(10)& "000" & trigger_times_i(11) ;
-- when others =>
-- s_word2 <= (others=>'0');
-- end generate;
--! Could also output data on trigger_i , but let's use the delayed signals. \n
--! The counters are one cicle delayed from the signal generation
--! The counters are one cycle delayed from the signal generation
s_FIFO_i(0) <= s_word0 when (s_event_strobe_d1 = '1') else
s_word1 when (s_event_strobe_d2 = '1') else
s_word2 when (s_event_strobe_d3 = '1') else
s_word2 when (s_event_strobe_d3_opt = '1') else
(others => '0');
--! If there is data in the FIFO output we put the strobe signal at high level.
s_FIFO_wr(0) <= s_event_strobe_d1 or s_event_strobe_d2 or s_event_strobe_d3;
s_FIFO_wr(0) <= s_event_strobe_d1 or s_event_strobe_d2 or s_event_strobe_d3_opt;
s_FIFO_wr(1) <= shutter_i_d1 xor shutter_i_d2;
s_evttype(1) <= "0011" when shutter_i_d1 = '1' and shutter_i_d2 = '0' else
......
......@@ -91,6 +91,7 @@ BEGIN
ipbus_o.ipb_rdata(31 downto 8) <= ( others => '0');
ipbus_o.ipb_err <= '1'; -- never return an error.
END ARCHITECTURE rtl;
......@@ -20,7 +20,7 @@ architecture rtl of ipbus_ver is
begin
ipbus_out.ipb_rdata <= X"a5e3" & X"1008"; -- Lower 16b are ipbus firmware build ID (temporary arrangement).
ipbus_out.ipb_rdata <= X"a5e4" & X"1008"; -- Lower 16b are ipbus firmware build ID (temporary arrangement).
ipbus_out.ipb_ack <= ipbus_in.ipb_strobe;
ipbus_out.ipb_err <= '0';
......
......@@ -114,12 +114,14 @@ ARCHITECTURE rtl OF logic_clocks IS
signal s_logic_clk_generator : std_logic_vector(3 downto 0) := "1100"; --! Stores state of 40MHz "clock"
signal s_strobe_fb : std_logic := '0';
signal s_logic_reset_ipb : std_logic := '0';
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 : std_logic := '0';
-- ! reset signal clocked onto logic-clock domain.
signal s_ipbus_ack : std_logic := '0';
signal s_reset_pll : std_logic := '0';
--signal s_Reset : std_logic := '0';
-- ! Global Reset signal
......@@ -149,6 +151,9 @@ BEGIN
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;
end if;
......@@ -173,7 +178,7 @@ BEGIN
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;
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 <= s_logic_reset_d2 and ( not s_logic_reset_d3);
......@@ -297,11 +302,12 @@ BEGIN
-- Status and control signals
LOCKED => s_locked_pll,
-- RST => s_logic_clk_rst,
RST => Reset_i or s_logic_reset, --'0',
RST => s_reset_pll,
-- Input clock control
CLKFBIN => s_clkfbout_buf,
CLKIN => s_clk);
s_reset_pll <= Reset_i or s_logic_reset;
-- Buffer the 16x clock and generate the ISERDES strobe signal
BUFPLL_inst : BUFPLL
......
......@@ -38,6 +38,7 @@
--!
--! <b>Modified by:</b>\n
--! Author:
--! David Cussans, 26/2/14 - Added registers to output to aid timing closure.
-------------------------------------------------------------------------------
--! \n\n<b>Last changes:</b>\n
-------------------------------------------------------------------------------
......
--=============================================================================
--! @file serdesCalibrateFSM_rtl.vhd
--=============================================================================
--
-------------------------------------------------------------------------------
-- --
-- UoB , USC
-- --
------------------------------------------------------------------------------- --
--
--! @brief Finite-state machine to control calibration and reset signals to
--! Iserdes, IDelay
--! based on code by Alvaro Dosil\n
--
--! @author Alvaro Dosil (David Cussans , David.Cussans@bristol.ac.uk)
--
--! @date 22/Feb/2014
--
--! @version v0.1
--
--! @details
--
-------------------------------------------------------------------------------
--! \n\n<b>Last changes:</b>\n
-------------------------------------------------------------------------------
--! @todo Implement a periodic calibration sequence\n
--! <another thing to do> \n
-
LIBRARY ieee;
USE ieee.std_logic_1164.all;
entity serdesCalibrateFSM is
port (
serdes_reset_i : in std_logic; --! Take high to start calibration
fsm_clock_i : in std_logic;
busy_idelay_m_i , busy_idelay_m_i : in std_logic; --! Status of IDELAY elements.
calibrate_o , reset_o : out std_logic --! Output from FSM to calibrate and reset lines
);
end entity serdesCalibrateFSM;
architecture rtl of serdesCalibrateFSM is
signal s_calibration : std_logic := '0'; -- Start calibration
--! Calibration FSM state values
type state_values is (st0, st1, st2, st3, st4);
signal pres_state, next_state: state_values := st0;
signal s_initial_cal : std_logic := '1'; -- Start up calibration flag
signal s_rst_FSM : std_logic := '0'; -- IODELAY reset
begin -- rtl
--! Calibration start condition
s_calibration <= serdes_reset_i or s_initial_cal;
--! Calibration FSM register
statereg: process(fabricClk_i, serdes_reset_i)
begin
if rising_edge(fabricClk_i) then
pres_state <= next_state; -- Move to next state
end if;
end process statereg;
--! Calibration FSM combinational block
fsm: process(pres_state, s_calibration, s_busy_idelay_m)
begin
next_state <= pres_state;
-- Default values
s_Rst_FSM <= '0';
s_cal_FSM <= '0';
case pres_state is
-- st0 - IDLE
when st0=>
if ( s_calibration = '1') then
next_state <= st1; -- Next state is "st1 - SEND CALIBRATION SIGNAL"
end if;
-- st1 - SEND CALIBRATION SIGNAL
when st1=>
s_cal_FSM <= '1';
s_initial_cal <= '0';
if s_busy_idelay_m = '1' then
next_state <= st2; -- Next state is "st2 - WAIT BUSY = '0'"
end if;
-- st2 - WAIT BUSY = '0'
when st2=>
if s_busy_idelay_m = '0' then
next_state <= st3; -- Next state is "st3 - RESET STATE"
end if;
-- st3 - RESET STATE
when st3=>
s_Rst_FSM <= '1';
if s_busy_idelay_m = '1' then
next_state <= st4; -- Next state is "st4 - WAIT BUSY = '0'"
end if;
-- st4 - WAIT BUSY = '0'
when st4=>
if s_busy_idelay_m = '0' then
next_state <= st0; -- Next state is "st0 - IDLE"
end if;
end case;
end process fsm;
calibrate_o <= s_cal_FSM;
reset_o <= s_Rst_FSM;
end rtl;
--=============================================================================
--! @file synchronizeRegisters_rtl.vhd
--=============================================================================
--
-------------------------------------------------------------------------------
-- --
-- University of Bristol, High Energy Physics Group.
-- --
------------------------------------------------------------------------------- --
-- VHDL Architecture worklib.synchronizeRegisters.rtl
--
--! @brief Regularly transfers the input to the output.\n
--! One clock for input , one clock for output\n
--! Can't just put entire bus through a couple of register stages,\n
--! Since this will just swap meta-stability issues for race issues.
--
--! @author David Cussans , David.Cussans@bristol.ac.uk
--
--! @date 24/Nov/12
--
--! @version v0.1
--
--! @details A six stage "ring oscillator" is used to generate two strobes.
--! One reads data into a register. The other registers the data to the output
--! Three stages are clocked on clk_write_i , three stages are clocked on clk_read_i
--! The time taken for an edge to travel round the complete loop is
--! 2 cycles of clk_read_i and 2 cycles of clk_write_i plus two intervals
--! that depend on the relative phase of clk_read_i and clk_write_i
--!
--! Based on registerCounters
--!
--! <b>Dependencies:</b>\n
--!
--! <b>References:</b>\n
--!
--! <b>Modified by:</b>\n
--! Author:
--! David Cussans, 26/2/14 - Added registers to output to aid timing closure.
-------------------------------------------------------------------------------
--! \n\n<b>Last changes:</b>\n
-------------------------------------------------------------------------------
--! @todo <next thing to do> \n
--! <another thing to do> \n
--
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
--use work.fmcTLU.all;
use work.ipbus_reg_types.all;
entity synchronizeRegisters is
generic (
--g_DATA_WIDTH : positive := 15;
g_NUM_REGISTERS : positive := 1); -- ! Width of counter
port (
clk_input_i : in std_logic; -- ! clock for input
data_i : in ipb_reg_v(g_NUM_REGISTERS-1 downto 0); -- ! array of registers to transfer to output
data_o : out ipb_reg_v(g_NUM_REGISTERS-1 downto 0); -- ! Data now in clk_output_i domain
clk_output_i : in std_logic); -- ! clock for output
end synchronizeRegisters;
architecture rtl of synchronizeRegisters is
signal s_ring_d0 , s_ring_d1 , s_ring_d2 , s_ring_d3 , s_ring_d4, s_ring_d5: std_logic := '0'; -- stages in "ring oscillator" used to generate strobes
signal s_registered_data : ipb_reg_v(data_i'range) := ( others => ( others => '0')); -- ! Register to store data between clock domains
signal s_read_strobe , s_write_strobe : std_logic := '0'; -- ! Strobes high to register data from input and to output
begin -- rtl
-- purpose: part of "ring oscillator" transfering strobe between clock domains
-- type : combinational
-- inputs : clk_read_i
-- outputs:
p_gen_capture_strobe: process (clk_input_i)
begin -- process p_gen_capture_strobe
if rising_edge(clk_input_i) then
s_ring_d0 <= not s_ring_d5;
s_ring_d1 <= s_ring_d0;
s_ring_d2 <= s_ring_d1;
if s_read_strobe = '1' then
s_registered_data <= data_i;
end if;
end if;
end process p_gen_capture_strobe;
s_read_strobe <= s_ring_d1 xor s_ring_d2; --! Generate a strobe with
--width one clk_read_i
-- purpose: part of "ring oscillator" transfering strobe between clock domains
-- type : combinational
-- inputs : clk_output_i
-- outputs:
p_gen_output_strobe: process (clk_output_i)
begin -- process p_gen_output_strobe
if rising_edge(clk_output_i) then
s_ring_d3 <= s_ring_d2;
s_ring_d4 <= s_ring_d3;
s_ring_d5 <= s_ring_d4;
if s_write_strobe = '1' then
data_o <= s_registered_data;
end if;
end if;
end process p_gen_output_strobe;
s_write_strobe <= s_ring_d4 xor s_ring_d5; --! Generate a strobe
--
end rtl;
......@@ -44,6 +44,8 @@ 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;
library unisim ;
......@@ -51,7 +53,8 @@ use unisim.vcomponents.all;
ENTITY triggerInputs IS
GENERIC(
g_NUM_INPUTS : natural := 1
g_NUM_INPUTS : natural := 1;
g_IPBUS_WIDTH : positive := 32
);
PORT(
cfd_discr_p_i : IN std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0);--! Inputs from constant-fraction discriminators
......@@ -82,14 +85,16 @@ END ENTITY triggerInputs ;
--
ARCHITECTURE rtl OF triggerInputs IS
signal s_rst_iserdes, s_rst_iserdes_ipb : std_logic := '0'; --! Reset ISERDES and calibrate IODELAY
signal s_rst_iserdes : std_logic := '0'; --! Reset ISERDES and calibrate IODELAY
signal s_threshold_discr_input , s_cfd_discr_input : std_logic_vector(g_NUM_INPUTS-1 downto 0); --! inputs from comparator
type t_deserialized_trigger_data_array is array ( natural range <> ) of std_logic_vector(7 downto 0); --
signal s_deserialized_threshold_data , s_deserialized_cfd_data : t_deserialized_trigger_data_array(g_NUM_INPUTS-1 downto 0);
type t_deserialized_trigger_data_array_l is array ( natural range <> ) of std_logic_vector(8 downto 0); --
signal s_deserialized_threshold_data_l , s_deserialized_cfd_data_l : t_deserialized_trigger_data_array_l(g_NUM_INPUTS-1 downto 0);
signal s_serdes_reset : std_logic := '0'; --! Take high to reset serdes and initiate IODELAY calibration
signal s_cfd_trigger_times : t_triggerTimeArray (g_NUM_INPUTS-1 DOWNTO 0);
......@@ -107,42 +112,54 @@ ARCHITECTURE rtl OF triggerInputs IS
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
BEGIN
ipbus_write: process (ipbus_clk_i)
begin -- process ipb_clk_i
if rising_edge(ipbus_clk_i) then
s_rst_iserdes_ipb <= '0';
constant c_N_CTRL : positive := 1;
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_serdes_reg : std_logic_vector(g_IPBUS_WIDTH-1 downto 0) := (others => '0');
signal s_counter_reset: std_logic := '0';
if (ipbus_i.ipb_strobe = '1' and ipbus_i.ipb_write = '1') then
case ipbus_i.ipb_addr(2 downto 0) is
when "000" => s_rst_iserdes_ipb <= ipbus_i.ipb_wdata(0) ; -- Calibrate IODELAY and reset ISERDES
when others => null;
end case;
end if;
s_ipbus_ack <= ipbus_i.ipb_strobe and not s_ipbus_ack;
end if;
end process ipbus_write;
BEGIN
-----------------------------------------------------------------------------
-- IPBUS read
-- IPBus interface
-----------------------------------------------------------------------------
ipbus_o.ipb_rdata <= (others => '1');
ipbus_o.ipb_ack <= s_ipbus_ack;
ipbus_o.ipb_err <= '0';
-- Can't get ipbus_syncreg_v to meet timing. So use non-syncronized followed
-- by synchronizer.
ipbus_registers: entity work.ipbus_ctrlreg_v
generic map (
N_STAT => c_N_STAT )
port map(
clk=> ipbus_clk_i,
reset => ipbus_reset_i ,
ipbus_in => ipbus_i,
ipbus_out => ipbus_o,
d=> s_status_to_ipbus,
q=> s_control_from_ipbus,
stb => open
);
sync_registers: entity work.synchronizeRegisters
generic map (
g_NUM_REGISTERS => c_N_STAT )
port map (
clk_input_i => clk_4x_logic,
data_i => s_status_to_ipbus,
data_o => s_sync_status_to_ipbus,
clk_output_i => ipbus_clk_i);
-- Map the control registers...
-- Register that controls IODELAY and ISERDES reset is at address 0
-- temporarily disable control signals ( need to register them to aid timing
-- closure... )
--s_reset_serdes_reg <= s_control_from_ipbus(0);
--s_rst_iserdes <= s_reset_serdes_reg(0);
--s_counter_reset <= s_reset_serdes_reg(1);
--s_reset_serdes_reg <= '0';
s_rst_iserdes <= '0';
s_counter_reset <= '0';
-- Change clock domain
p_signals_clk_domain: process (clk_4x_logic )
begin -- process p_internal_triggers
if rising_edge(clk_4x_logic) then
s_rst_iserdes <= s_rst_iserdes_ipb;
end if;
end process;
-----------------------------------------------------------------------------
-- Connect up trigger inputs to deserializers and a LUT to determine
......@@ -172,11 +189,12 @@ BEGIN
data_o => s_deserialized_threshold_data(triggerInput)
);
s_deserialized_threshold_data_l(triggerInput) <= s_deserialized_threshold_data(triggerInput) & s_threshold_previous_late_bit(triggerInput);
thresholdLUT : entity work.arrivalTimeLUT
port map (
clk_4x_logic_i => clk_4x_logic,
strobe_4x_logic_i => strobe_4x_logic_i,
deserialized_data_i => s_deserialized_threshold_data(triggerInput) & s_threshold_previous_late_bit(triggerInput),
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),
rising_edge_o => s_edge_rising(triggerInput),
......@@ -217,11 +235,12 @@ BEGIN
data_o => s_deserialized_CFD_data(triggerInput)
);
s_deserialized_CFD_data_l(triggerInput) <= s_deserialized_CFD_data(triggerInput) & s_CFD_previous_late_bit(triggerInput);
CFDLUT : entity work.arrivalTimeLUT
port map (
clk_4x_logic_i => clk_4x_logic,
strobe_4x_logic_i => strobe_4x_logic_i,
deserialized_data_i => s_deserialized_CFD_data(triggerInput) & s_CFD_previous_late_bit(triggerInput),
deserialized_data_i => s_deserialized_CFD_data_l(triggerInput),
first_rising_edge_time_o => s_cfd_trigger_times(triggerInput),
last_falling_edge_time_o => open,
rising_edge_o => s_CFD_rising_edge(triggerInput),
......@@ -237,10 +256,22 @@ BEGIN
end if ;
end process;
--! Instantiate counter for output triggers.
--! Input I is connected to address I+1
cmp_inputTriggerCounter : entity work.counterWithReset
generic map (
g_COUNTER_WIDTH => g_IPBUS_WIDTH)
port map (
clock_i => clk_4x_logic,
reset_i => s_counter_reset,
enable_i => s_edge_rising(triggerInput),
result_o => s_status_to_ipbus(triggerInput+1));
end generate trigger_input_loop;
trigger_debug_o( (g_NUM_INPUTS-1) downto 0) <= s_threshold_discr_input;
trigger_debug_o( ((2*g_NUM_INPUTS)-1) downto g_NUM_INPUTS) <= s_CFD_discr_input;
--trigger_debug_o( ((2*g_NUM_INPUTS)-1) downto g_NUM_INPUTS) <= s_CFD_discr_input;
trigger_debug_o( ((2*g_NUM_INPUTS)-1) downto g_NUM_INPUTS) <= s_edge_rising;
END ARCHITECTURE rtl;
......@@ -35,6 +35,8 @@
--! Author:
-------------------------------------------------------------------------------
--! \n\n<b>Last changes:</b>\n
--! Move all IPBus stuff into ipbus_syncreg_v , which also handles clock domain
--! crossing. 20/Feb/2014 , David Cussans
-------------------------------------------------------------------------------
--! @todo <next thing to do> \n
--! <another thing to do> \n
......@@ -48,6 +50,7 @@ USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;
USE work.ipbus.all;
use work.ipbus_reg_types.all;
ENTITY triggerLogic IS
GENERIC(
......@@ -92,73 +95,68 @@ ARCHITECTURE rtl OF triggerLogic IS
-- signal s_logic_reset , s_logic_reset_ipb : std_logic := '0'; -- ! Take high to reset counters etc.
signal s_pre_veto_trigger ,s_post_veto_trigger : std_logic := '0'; -- ! Can't read from an output port so keep internal copy
BEGIN
-----------------------------------------------------------------------------
-- IPBus write
-----------------------------------------------------------------------------
ipbus_write: process (ipbus_clk_i)
begin -- process ipb_clk_i
if rising_edge(ipbus_clk_i) then
if (ipbus_i.ipb_strobe = '1' and ipbus_i.ipb_write = '1') then
case ipbus_i.ipb_addr(2 downto 0) is
when "010" => s_internal_trigger_interval <= ipbus_i.ipb_wdata ; -- Interval between internal triggers in ticks of logic_strobe_i
when "011" => s_trigger_pattern_ipb <= ipbus_i.ipb_wdata ; -- trigger mask ( 16 bits for 4 inputs )
when "100" => s_internal_veto_ipb <= ipbus_i.ipb_wdata(0) ; -- bit-0 - internal trigger veto. Set to halt vetos.
when others => null;
end case;
constant c_N_CTRL : positive := 5;
constant c_N_STAT : positive := 6;
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_veto_word : std_logic_vector(g_IPBUS_WIDTH-1 downto 0) := (others => '0');
signal s_external_veto_word : std_logic_vector(g_IPBUS_WIDTH-1 downto 0) := (others => '0');
end if;
s_ipbus_ack <= ipbus_i.ipb_strobe and not s_ipbus_ack;
if (s_internal_trigger_interval = x"00000000") then
s_internal_trigger_active_ipb <= '0';
else
s_internal_trigger_active_ipb <= '1';
end if;
end if;
end process ipbus_write;
ipbus_o.ipb_ack <= s_ipbus_ack;
ipbus_o.ipb_err <= '0';
BEGIN
-----------------------------------------------------------------------------
-- IPBUS read
-- IPBus interface
-----------------------------------------------------------------------------
with ipbus_i.ipb_addr(2 downto 0) select
ipbus_o.ipb_rdata <=
s_post_veto_trigger_counter_ipb when "000",
s_pre_veto_trigger_counter_ipb when "001",
s_internal_trigger_interval when "010",
s_trigger_pattern_ipb when "011",
x"0000000" & "000" & s_internal_veto_ipb when "100",
(others => '1') when others;
register_trigger_pattern: entity work.sync_reg
generic map(g_Data_width => s_trigger_pattern_ipb'length)
ipbus_registers: entity work.ipbus_ctrlreg_v
generic map(
N_CTRL => c_N_CTRL,
N_STAT => c_N_STAT
)
port map(
clk_i => clk_4x_logic_i,
async_i => s_trigger_pattern_ipb,
sync_o => s_trigger_pattern
clk => ipbus_clk_i,
reset=> ipbus_reset_i ,
ipbus_in=> ipbus_i,
ipbus_out=> ipbus_o,
d=> s_sync_status_to_ipbus,
q=> s_control_from_ipbus,
stb=> open
);
-- Move the trigger pattern onto the logic clock domain to allow timing
-- constraints to be met.
-- register_trigger_pattern : entity work.registerCounter
-- generic map (
-- g_DATA_WIDTH => s_trigger_pattern_ipb'length )
-- port map (
-- clk_input_i => ipbus_clk_i,
-- data_i => s_trigger_pattern_ipb,
-- data_o => s_trigger_pattern,
-- clk_output_i => clk_4x_logic_i
-- );
-- 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_internal_trigger_interval <= s_sync_control_from_ipbus(2);
s_trigger_pattern <= s_sync_control_from_ipbus(3);
s_veto_word <= s_sync_control_from_ipbus(4);
s_internal_veto <= s_veto_word(0);
-- Map the status registers
s_status_to_ipbus(0) <= std_logic_vector(s_post_veto_trigger_counter);
s_status_to_ipbus(1) <= std_logic_vector(s_pre_veto_trigger_counter);
s_status_to_ipbus(2) <= s_internal_trigger_interval;
s_status_to_ipbus(3) <= s_trigger_pattern;
s_status_to_ipbus(4) <= s_veto_word;
s_status_to_ipbus(5) <= s_external_veto_word;
s_external_veto_word(0) <= veto_i;
-----------------------------------------------------------------------------
-- Generate triggers
......@@ -181,40 +179,16 @@ BEGIN
pre_veto_trigger_o <= s_pre_veto_trigger ;
post_veto_trigger_o <= s_post_veto_trigger;
-- purpose: Generates internal triggers a regular intervals set by s_internal_trigger_interval. Zero means no triggers
-- type : combinational
-- inputs : clk_4x_logic_i , logic_strobe_i
-- outputs: s_internal_trigger , s_internal_trigger_timer
-- p_internal_triggers: process (clk_4x_logic_i )
-- begin -- process p_internal_triggers
-- if rising_edge(clk_4x_logic_i) then
--
-- s_internal_trigger <= '0';
-- s_internal_trigger_active <= s_internal_trigger_active_ipb; -- move from
-- --IPBus clock to trigger
-- if s_internal_trigger_active = '1' then
--
-- if (s_internal_trigger_timer = unsigned(s_internal_trigger_interval)) then
-- s_internal_trigger <= '1';
-- s_internal_trigger_timer <= (others => '0');
-- else
-- s_internal_trigger <= '0';
-- s_internal_trigger_timer <= s_internal_trigger_timer + 1;
-- end if;
--
-- end if;
--
--
-- end if;
-- end process p_internal_triggers;
p_internal_triggers: process (clk_4x_logic_i )
begin -- process p_internal_triggers
if rising_edge(clk_4x_logic_i) then
s_internal_trigger_active <= s_internal_trigger_active_ipb; -- move from
-- IPBus clock to trigger
s_internal_veto <= s_internal_veto_ipb;
if (s_internal_trigger_interval = x"00000000") then
s_internal_trigger_active <= '0';
else
s_internal_trigger_active <= '1';
end if;
s_internal_trigger_timer_d <= s_internal_trigger_timer; -- Signal delayed
end if;
......@@ -256,46 +230,6 @@ BEGIN
end if;
end process p_trigger_counter;
register_pre_veto_trigs: entity work.sync_reg
generic map(g_Data_width => g_IPBUS_WIDTH)
port map(
clk_i => ipbus_clk_i,
async_i => std_logic_vector(s_pre_veto_trigger_counter),
sync_o => s_pre_veto_trigger_counter_ipb
);
register_post_veto_trigs: entity work.sync_reg
generic map(g_Data_width => g_IPBUS_WIDTH)
port map(
clk_i => ipbus_clk_i,
async_i => std_logic_vector(s_post_veto_trigger_counter),
sync_o => s_post_veto_trigger_counter_ipb
);
-- -- Transfer trigger counters to IPBUS clock domain
-- register_pre_veto_trigs : entity work.registerCounter
-- generic map (
-- g_DATA_WIDTH => g_IPBUS_WIDTH)
-- port map (
-- clk_input_i => clk_4x_logic_i,
-- data_i => std_logic_vector(s_pre_veto_trigger_counter),
-- data_o => s_pre_veto_trigger_counter_ipb,
-- clk_output_i => ipbus_clk_i
-- );
-- -- Transfer trigger counters to IPBUS clock domain
-- register_post_veto_trigs : entity work.registerCounter
-- generic map (
-- g_DATA_WIDTH => g_IPBUS_WIDTH)
-- port map (
-- clk_input_i => clk_4x_logic_i,
-- data_i => std_logic_vector(s_post_veto_trigger_counter),
-- data_o => s_post_veto_trigger_counter_ipb,
-- clk_output_i => ipbus_clk_i
-- );
event_number_o <= std_logic_vector(s_post_veto_trigger_counter);
END ARCHITECTURE rtl;
......
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