From 1b2c171c4cbe11a693815c6ad531c695888341bc Mon Sep 17 00:00:00 2001 From: David Gabriel Monk <david.gabriel.monk@cern.ch> Date: Tue, 8 Feb 2022 23:47:28 +0100 Subject: [PATCH] Update emp-fwk to master branch --- .../firmware/hdl/emp_device_decl_sm1_v1.vhd | 6 +- .../firmware/hdl/emp_top_pcie_both_ttc.vhd | 11 +- .../firmware/ucf/clock_constraints_common.tcl | 52 ++ .../firmware/ucf/clock_declarations_pcie.tcl | 12 + .../components/ttc/firmware/hdl/emp_ttc.vhd | 589 ++++++++++++++++++ top/firmware/hdl/emp_project_decl.vhd | 4 +- 6 files changed, 661 insertions(+), 13 deletions(-) create mode 100644 replacements/emp-fwk/components/top/firmware/ucf/clock_constraints_common.tcl create mode 100644 replacements/emp-fwk/components/top/firmware/ucf/clock_declarations_pcie.tcl create mode 100644 replacements/emp-fwk/components/ttc/firmware/hdl/emp_ttc.vhd diff --git a/replacements/emp-fwk/boards/serenity/dc_ku15p/firmware/hdl/emp_device_decl_sm1_v1.vhd b/replacements/emp-fwk/boards/serenity/dc_ku15p/firmware/hdl/emp_device_decl_sm1_v1.vhd index d73c017f..9a9ce169 100644 --- a/replacements/emp-fwk/boards/serenity/dc_ku15p/firmware/hdl/emp_device_decl_sm1_v1.vhd +++ b/replacements/emp-fwk/boards/serenity/dc_ku15p/firmware/hdl/emp_device_decl_sm1_v1.vhd @@ -7,8 +7,6 @@ library IEEE; use IEEE.STD_LOGIC_1164.all; -use work.tcds2_interface_pkg; - use work.emp_framework_decl.all; @@ -16,7 +14,9 @@ package emp_device_decl is constant BOARD_DESIGN_ID : std_logic_vector(7 downto 0) := X"41"; - constant TCDS2_MGT_TYPE : tcds2_interface_pkg.mgt_type_t := tcds2_interface_pkg.MGT_TYPE_GTYE4; + constant TCDS2_MGT_TYPE : io_gt_kind_t := io_gty; + constant TCDS2_SPEED : io_tcds2_speed_t := io_tcds2_10g; + constant N_REGION : integer := 18; constant N_REFCLK : integer := 14; diff --git a/replacements/emp-fwk/components/top/firmware/hdl/emp_top_pcie_both_ttc.vhd b/replacements/emp-fwk/components/top/firmware/hdl/emp_top_pcie_both_ttc.vhd index 3d5e02b0..4325d53f 100644 --- a/replacements/emp-fwk/components/top/firmware/hdl/emp_top_pcie_both_ttc.vhd +++ b/replacements/emp-fwk/components/top/firmware/hdl/emp_top_pcie_both_ttc.vhd @@ -97,10 +97,10 @@ architecture rtl of top is signal rsts_aux : std_logic_vector(2 downto 0); -- TTC signals - signal ttc_l1a, ttc_l1a_dist, dist_lock, oc_flag, ec_flag, payload_bc0, ttc_l1a_throttle : std_logic; + signal ttc_l1a, ttc_l1a_dist, dist_lock, oc_flag, ec_flag, ttc_l1a_throttle : std_logic; signal ttc_cmd, ttc_cmd_dist : ttc_cmd_t; signal bunch_ctr : bctr_t; - signal evt_ctr, orb_ctr : eoctr_t; + signal orb_ctr : eoctr_t; -- Others signal nuke, soft_rst : std_logic; @@ -243,7 +243,7 @@ begin ttc_l1a_dist => ttc_l1a_dist, dist_lock => dist_lock, bunch_ctr => bunch_ctr, - evt_ctr => evt_ctr, + evt_ctr => (others => '0'), orb_ctr => orb_ctr, oc_flag => oc_flag, ec_flag => ec_flag, @@ -269,10 +269,6 @@ begin ctrs_out => ctrs, rst_out => rst_loc, clken_out => clken_loc, - --cap_bus => cap_bus, - --daq_bus_in => daq_bus_top, - --daq_bus_out => daq_bus_bot, - payload_bc0 => payload_bc0, refclkp => refclkp, refclkn => refclkn, clkmon => clkmon, @@ -290,6 +286,7 @@ begin rst => ipb_rst, ipb_in => ipb_w_array(N_SLV_PAYLOAD), ipb_out => ipb_r_array(N_SLV_PAYLOAD), + clk40 => clk40, clk_payload => clks_aux, rst_payload => rsts_aux, clk_p => clk_p, diff --git a/replacements/emp-fwk/components/top/firmware/ucf/clock_constraints_common.tcl b/replacements/emp-fwk/components/top/firmware/ucf/clock_constraints_common.tcl new file mode 100644 index 00000000..fb9fdc0f --- /dev/null +++ b/replacements/emp-fwk/components/top/firmware/ucf/clock_constraints_common.tcl @@ -0,0 +1,52 @@ +# 40MHz & payload I/O clocks derived from board-local source (for tests without external clock source) +create_generated_clock -name clk_40_pseudo_i [get_pins ttc/bufgce_clk_40_rx/O] +create_generated_clock -name clk_40_pseudo -source [get_pins ttc/clocks/mmcm/CLKIN2] [get_pins ttc/clocks/mmcm/CLKOUT1] +create_generated_clock -name clk_payload_pseudo -source [get_pins ttc/clocks/mmcm/CLKIN2] [get_pins ttc/clocks/mmcm/CLKOUT3] + +# Names of the LHC-synchronised derived clocks that are used by payload and infra (outside of TTC block) +lappend lMainInternalClocks clk_40_pseudo clk_payload_pseudo + + +if {[llength [get_pins -quiet ttc/gen_master_legacy.osc_clock/mmcm/CLKOUT1]] != 0} { + create_generated_clock -name clk_40_extern_i0 [get_pins ttc/gen_master_legacy.osc_clock/gen_mmcm/mmcm/CLKOUT1] +} + +if {[llength [get_pins -quiet ttc/gen_master_tcds2.tcds2/tcds2_interface/bufgce_clk_40_rx/O]] != 0} { + create_generated_clock -name clk_40_extern_i1 [get_pins ttc/gen_master_tcds2.tcds2/tcds2_interface/bufgce_clk_40_rx/O] +} + +foreach i [list 0 1] { + if {[llength [get_clocks -quiet clk_40_extern_i$i]] != 0 } { + create_generated_clock -name clk_40_extern$i -master_clock [get_clocks clk_40_extern_i$i] [get_pins ttc/clocks/mmcm/CLKOUT1] + # Payload I/O clock derived from external oscillator + create_generated_clock -name clk_payload_extern$i -master_clock [get_clocks clk_40_extern_i$i] [get_pins ttc/clocks/mmcm/CLKOUT3] + + lappend lMainInternalClocks clk_40_extern_i$i clk_40_extern$i clk_payload_extern$i + } +} + + +# Clock groups: Asynchronous +puts "lMainInternalClocks = $lMainInternalClocks" +set_clock_groups -asynch -group [get_clocks axi_clk] -group [get_clocks -include_generated_clocks ipbus_clk] +set_clock_groups -asynch -group [get_clocks -include_generated_clocks ipbus_clk] -group $lMainInternalClocks + +# Clock groups: Logically exclusive +# The 40MHz, 160MHz and payload clocks used across the chip are generated by an MMCM with two clock sources: +# * an externally-provided LHC clock (typically from TCDS), which itself could come from one of two interfaces (clk_40_externN); and +# * an internally-generated 'pseudo-LHC' clock (clk_40_pseudo) +# Must set the copies of the clocks generated from those sources as logically exclusive +foreach lMasterA [list clk_40_pseudo_i clk_40_pseudo_i clk_40_extern_i0] lMasterB [list clk_40_extern_i0 clk_40_extern_i1 clk_40_extern_i1] { + if {[llength [get_clocks -quiet [list $lMasterA $lMasterB]]] == 2} { + puts "Declaring clocks derived from $lMasterA and $lMasterB as logically exclusive" + set_clock_groups -logically_exclusive -group [get_clocks -filter "MASTER_CLOCK == $lMasterA"] -group [get_clocks -filter "MASTER_CLOCK == $lMasterB"] + } +} + + +# Remove timing constraints for heartbeat LED output port +set_false_path -to [get_ports -regexp "(.+_led|led_.+)"] + +# Print clock report for the record (in case build fails, or need to debug clock-related issues) +report_clocks + diff --git a/replacements/emp-fwk/components/top/firmware/ucf/clock_declarations_pcie.tcl b/replacements/emp-fwk/components/top/firmware/ucf/clock_declarations_pcie.tcl new file mode 100644 index 00000000..e49c9d01 --- /dev/null +++ b/replacements/emp-fwk/components/top/firmware/ucf/clock_declarations_pcie.tcl @@ -0,0 +1,12 @@ + +# 100 Mhz PCIe system clock +create_clock -period 10.000 -name pcie_sys_clk [get_ports pcie_sys_clk_p] + +# IPbus clock +create_generated_clock -name ipbus_clk -source [get_pins infra/clocks/mmcm/CLKIN1] [get_pins infra/clocks/mmcm/CLKOUT1] + +# AXI clock +create_generated_clock -name axi_clk [get_pins -hierarchical -filter {NAME =~infra/dma/xdma/*/phy_clk_i/bufg_gt_userclk/O}] + +# Approx 40MHz clock derived from AXI clock (for tests without external clock source) +#create_generated_clock -name clk_40_pseudo_i [get_pins infra/clocks/mmcm/CLKOUT2] diff --git a/replacements/emp-fwk/components/ttc/firmware/hdl/emp_ttc.vhd b/replacements/emp-fwk/components/ttc/firmware/hdl/emp_ttc.vhd new file mode 100644 index 00000000..bf1c409c --- /dev/null +++ b/replacements/emp-fwk/components/ttc/firmware/hdl/emp_ttc.vhd @@ -0,0 +1,589 @@ +-- ttc +-- +-- TTC decoder, counters, LHC clock distribution, etc +-- +-- Dave Newbold, June 2013 + +library IEEE; +use IEEE.STD_LOGIC_1164.all; +use ieee.numeric_std.all; + +library unisim; +use unisim.VComponents.all; + +use work.ipbus.all; +use work.ipbus_reg_types.all; +use work.ipbus_decode_emp_ttc.all; +use work.emp_ttc_decl.all; +use work.emp_ttc_utils; + +use work.emp_device_decl; +use work.emp_project_decl.all; + +use work.tcds2_interface_pkg; +use work.tcds2_streams_pkg; + + +------------------------------------------------------------------------------- +entity emp_ttc is + generic( + ENABLE_LEGACY_TTC : boolean; + ENABLE_TCDS2 : boolean; + EXT_CLK_FREQ : real + ); + port( + -- ipbus clock & rst + clk_ipb : in std_logic; + rst_ipb : in std_logic; + -- IPBus + ipb_in : in ipb_wbus; + ipb_out : out ipb_rbus; + -- 125MHz clock + clk125 : in std_logic; + -- internal pseudo-40MHz clock + clk40ish_in : in std_logic; + -- clock outputs + clk40 : out std_logic; + -- clock domain reset outputs + rst40 : out std_logic; + clk_p : out std_logic; + rst_p : out std_logic; + clks_aux : out std_logic_vector(2 downto 0); + rsts_aux : out std_logic_vector(2 downto 0); + -- Legacy TTC interface + ttc_clk_p : in std_logic; + ttc_clk_n : in std_logic; + ttc_rx_p : in std_logic; + ttc_rx_n : in std_logic; + -- TCDS2 interface + tcds_clk_p : in std_logic; + tcds_clk_n : in std_logic; + tcds_rx_p : in std_logic; + tcds_rx_n : in std_logic; + tcds_tx_p : out std_logic; + tcds_tx_n : out std_logic; + -- TTC b command output + ttc_cmd : out ttc_cmd_t; + ttc_cmd_dist : out ttc_cmd_t; + -- L1A output + ttc_l1a : out std_logic; + -- L1A qualifier output + ttc_l1a_dist : out std_logic; + dist_lock : in std_logic; + bunch_ctr : out bctr_t; + evt_ctr : in eoctr_t; + orb_ctr : out eoctr_t; + oc_flag : out std_logic; + ec_flag : out std_logic; + -- clock monitoring inputs from MGTs + monclk : in std_logic_vector(3 downto 0); + clk125_o : out std_logic + ); + +end emp_ttc; +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +architecture rtl of emp_ttc is + + signal clk40_ext, clk40_ext_legacy, clk40_ext_tcds2 : std_logic; + signal tcds_refclk_b, tcds_refclk_div : std_logic; + signal clk40_i, rst40_i, clk160s, clk40_div, rsti, rsti_40, clk40_a, rst40_a, clk_p_i, rst_p_i : std_logic; + signal lock, stop : std_logic; + signal clks_aux_i, rsts_aux_i : std_logic_vector(2 downto 0); + signal l1a_ext_legacy, l1a_ext_tcds2 : std_logic; + signal l1a, l1a_ttc, l1a_del, l1a_ext, l1a_pend, cmd_bx, cmd_pend, l1a_issue, cmd_issue : std_logic; + signal cmd, cmd_ttc, cmd_del, cmd_ext_tcds2, cmd_ext_legacy : ttc_cmd_t; + signal psok, bc0_fr, ctr_clr : std_logic; + signal bunch_ctr_i : bctr_t; + signal req_bx : unsigned(bctr_t'range); + signal orb_ctr_i : eoctr_t; + signal clk40_mmcm_sel : std_logic; + + signal stat_clk40 : ipb_reg_v(0 downto 0); + signal ctrl_clk40 : ipb_reg_v(0 downto 0); + + signal stat_common : ipb_reg_v(2 downto 0); + signal ctrl_common : ipb_reg_v(0 downto 0); + signal stb_common : std_logic_vector(0 downto 0); + + signal bc0_lock : std_logic; + signal ipbw : ipb_wbus_array(N_SLAVES - 1 downto 0); + signal ipbr : ipb_rbus_array(N_SLAVES - 1 downto 0); + + signal clk_40_to_mmcm : std_logic; + +begin + + + +-- ipbus address decode + + fabric : entity work.ipbus_fabric_sel + generic map( + NSLV => N_SLAVES, + SEL_WIDTH => IPBUS_SEL_WIDTH) + port map( + ipb_in => ipb_in, + ipb_out => ipb_out, + sel => ipbus_sel_emp_ttc(ipb_in.ipb_addr), + ipb_to_slaves => ipbw, + ipb_from_slaves => ipbr + ); + +-- TTC control registers + + reg_clk40 : entity work.ipbus_ctrlreg_v + generic map ( + N_CTRL => 1, + N_STAT => 1 + ) + port map ( + clk => clk_ipb, + reset => rst_ipb, + ipbus_in => ipbw(N_SLV_CLK40), + ipbus_out => ipbr(N_SLV_CLK40), + d => stat_clk40, + q => ctrl_clk40, + stb => open + ); + + stat_clk40(0)(0) <= lock; + stat_clk40(0)(1) <= stop; + + reg_common : entity work.ipbus_syncreg_v + generic map( + N_CTRL => 1, + N_STAT => 3 + ) + port map( + clk => clk_ipb, + rst => rst_ipb, + ipb_in => ipbw(N_SLV_MASTER_COMMON), + ipb_out => ipbr(N_SLV_MASTER_COMMON), + slv_clk => clk40_a, + d => stat_common, + q => ctrl_common, + stb => stb_common + ); + + stat_common(0)(0) <= '1' when ENABLE_LEGACY_TTC else '0'; + stat_common(0)(1) <= '1' when ENABLE_TCDS2 else '0'; + + + -- Mux for external clocks + gen_ext_mux : if ENABLE_TCDS2 and ENABLE_LEGACY_TTC generate + + signal sel_pipeline : std_logic_vector(3 downto 0); + + begin + + process (clk_ipb) + begin + if rising_edge(clk_ipb) then + sel_pipeline(0) <= ctrl_clk40(0)(2); + sel_pipeline(1) <= sel_pipeline(0); + sel_pipeline(2) <= sel_pipeline(1); + sel_pipeline(3) <= sel_pipeline(2); + end if; + end process; + + clk40mux : BUFGMUX + port map ( + S => sel_pipeline(3), + I0 => clk40_ext_legacy, + I1 => clk40_ext_tcds2, + O => clk40_ext + ); + + elsif ENABLE_TCDS2 generate + + clk40_ext <= clk40_ext_tcds2; + + else generate + + clk40_ext <= clk40_ext_legacy; + + end generate; + + +-- MMCM for clock multiplication / phase adjustment + + rsti <= rst_ipb or ctrl_common(0)(2); + clk40_mmcm_sel <= ctrl_clk40(0)(1) or ctrl_clk40(0)(2); + + bufgce_clk_40_rx : bufgce_div + generic map ( + BUFGCE_DIVIDE => 8 + ) + port map ( + i => tcds_refclk_b, + o => clk_40_to_mmcm, + ce => '1', + clr => '0' + ); + + clocks : entity work.emp_ttc_clocks + port map( + clk_40 => clk40_ext, + clk_40pseudo => clk_40_to_mmcm, + clko_40 => clk40_i, + clko_p => clk_p_i, + clko_aux => clks_aux_i, + rsto_40 => rst40_i, + rsto_p => rst_p_i, + rsto_aux => rsts_aux_i, + clko_160s => clk160s, + stopped => stop, + locked => lock, + rst_mmcm => ctrl_clk40(0)(0), + rsti => rsti_40, + clksel => clk40_mmcm_sel, + psval => ctrl_common(0)(23 downto 12), + psok => psok, + psen => ctrl_common(0)(24) + ); + + clk40_a <= clk40_i; -- Needed to make sure delta delays line up in simulation! + rst40_a <= rst40_i; + clk40 <= clk40_i; + rst40 <= rst40_i; + clk_p <= clk_p_i; + rst_p <= rst_p_i; + clks_aux <= clks_aux_i; + rsts_aux <= rsts_aux_i; + +-- TTC protocol decoder + + gen_master_tcds2 : if ENABLE_TCDS2 generate + + signal clk125_i, clk125_b : std_logic; + signal tcds_refclk : std_logic; + signal tcds_refclk_i : std_logic; + signal tcds_orbit_pulse : std_logic; + + signal channel0_ttc2, channel1_ttc2 : tcds2_streams_pkg.tcds2_ttc2; + signal tcds2_interface_ctrl : tcds2_interface_pkg.tcds2_interface_ctrl_t; + signal tcds2_interface_stat : tcds2_interface_pkg.tcds2_interface_stat_t; + + begin + + clk125_o <= clk125_b; + + ibufds_gt : IBUFDS_GTE4 + port map ( + i => tcds_clk_p, + ib => tcds_clk_n, + o => tcds_refclk, + odiv2 => tcds_refclk_i, + ceb => '0' + ); + + ibuf_osc : IBUF + port map ( + O => clk125_i, + I => clk125 + ); + + bufg_osc : BUFG + port map ( + I => clk125_i, + O => clk125_b + ); + + bufg_ref : BUFG_GT + port map ( + i => tcds_refclk_i, + o => tcds_refclk_b, + ce => '1', + clr => '0', + div => "000", + cemask => '1', + clrmask => '0' + ); + + tcds2 : entity work.tcds2_interface_with_mgt + generic map ( + G_MGT_TYPE => emp_ttc_utils.get_tcds2_mgt_type(emp_device_decl.TCDS2_MGT_TYPE), + G_LINK_SPEED => emp_ttc_utils.get_tcds2_link_speed(emp_device_decl.TCDS2_SPEED), + G_INCLUDE_PRBS_LINK_TEST => true + ) + port map ( + ctrl_i => tcds2_interface_ctrl, + stat_o => tcds2_interface_stat, + + clk_sys_125mhz => clk125_b, + + mgt_tx_p_o => tcds_tx_p, + mgt_tx_n_o => tcds_tx_n, + mgt_rx_p_i => tcds_rx_n, + mgt_rx_n_i => tcds_rx_p, + + clk_320_mgt_ref_i => tcds_refclk, + + clk_40_o => clk40_ext_tcds2, + + orbit_o => tcds_orbit_pulse, + + channel0_ttc2_o => channel0_ttc2, + channel0_tts2_i(0) => tcds2_streams_pkg.C_TCDS2_TTS2_VALUE_IGNORED, + channel1_ttc2_o => channel1_ttc2, + channel1_tts2_i(0) => tcds2_streams_pkg.C_TCDS2_TTS2_VALUE_IGNORED + ); + + process (clk40_a) + begin + if rising_edge(clk40_a) then + -- Only consider a BC0 signal to be received if I see it on both of those channels in the same BX + -- Reason: Improve robustness against bitflips in TTC path for Serenity + -- TODO: Set this behvaviour using SW-settable register in v0.7.0, rather than hardcoding + if (channel0_ttc2.sync_flags_and_commands(0) = '1') and (channel1_ttc2.sync_flags_and_commands(0) = '1') then + cmd_ext_tcds2 <= TTC_BCMD_BC0; + else + cmd_ext_tcds2 <= TTC_BCMD_NULL; + end if; + + rsti_40 <= rsti; + + end if; + end process; + + l1a_ext_tcds2 <= '0'; + + csr : entity work.ipbus_tcds2_interface_accessor + port map ( + clk_ipb => clk_ipb, + rst_ipb => rst_ipb, + ipb_in => ipbw(N_SLV_MASTER_TCDS2), + ipb_out => ipbr(N_SLV_MASTER_TCDS2), + + ctrl_o => tcds2_interface_ctrl, + stat_i => tcds2_interface_stat + ); + + else generate + + tcds_tx_p <= '0'; + tcds_tx_n <= '0'; + + tcds_refclk_b <= '0'; + clk40_ext_tcds2 <= '0'; + cmd_ext_tcds2 <= TTC_BCMD_NULL; + l1a_ext_tcds2 <= '0'; + + ipbr(N_SLV_MASTER_TCDS2).ipb_ack <= '0'; + ipbr(N_SLV_MASTER_TCDS2).ipb_err <= ipbw(N_SLV_MASTER_TCDS2).ipb_strobe; + ipbr(N_SLV_MASTER_TCDS2).ipb_rdata <= (others => '0'); + + end generate; + + + gen_master_legacy : if ENABLE_LEGACY_TTC generate + + signal err_rst : std_logic; + signal sinerr_ctr, dblerr_ctr : std_logic_vector(15 downto 0); + signal stat_legacy : ipb_reg_v(0 downto 0); + signal ctrl_legacy : ipb_reg_v(0 downto 0); + signal stb_legacy : std_logic_vector(0 downto 0); + + begin + + osc_clock : entity work.emp_oscclk + generic map ( + OSC_FREQ => EXT_CLK_FREQ + ) + port map ( + clk_p => ttc_clk_p, + clk_n => ttc_clk_n, + clk40 => clk40_ext_legacy + ); + + reg : entity work.ipbus_syncreg_v + generic map( + N_CTRL => 1, + N_STAT => 1 + ) + port map( + clk => clk_ipb, + rst => rst_ipb, + ipb_in => ipbw(N_SLV_MASTER_LEGACY), + ipb_out => ipbr(N_SLV_MASTER_LEGACY), + slv_clk => clk40_a, + d => stat_legacy, + q => ctrl_legacy, + stb => stb_legacy + ); + + interface : entity work.emp_ttc_legacy + port map( + clk => clk40_a, + rst => rst40_a, + sclk => clk160s, + sclk_locked => lock, + ttc_in_p => ttc_rx_p, + ttc_in_n => ttc_rx_n, + l1a => l1a_ext_legacy, + cmd => cmd_ext_legacy, + sinerr_ctr => sinerr_ctr, + dblerr_ctr => dblerr_ctr, + err_rst => err_rst + ); + + err_rst <= ctrl_legacy(0)(0) and stb_legacy(0); + stat_legacy(0) <= dblerr_ctr & sinerr_ctr; + + + else generate + + clk40_ext_legacy <= '0'; + cmd_ext_legacy <= TTC_BCMD_NULL; + l1a_ext_legacy <= '0'; + + ipbr(N_SLV_MASTER_LEGACY).ipb_ack <= '0'; + ipbr(N_SLV_MASTER_LEGACY).ipb_err <= ipbw(N_SLV_MASTER_LEGACY).ipb_strobe; + ipbr(N_SLV_MASTER_LEGACY).ipb_rdata <= (others => '0'); + + end generate; + + + -- FIXME: Select between each of two external sources and internal + with ctrl_common(0)(1 downto 0) select cmd_ttc <= + cmd_ext_legacy when "01", + cmd_ext_tcds2 when "10", + TTC_BCMD_NULL when others; + + with ctrl_common(0)(1 downto 0) select l1a_ttc <= + l1a_ext_legacy when "01", + l1a_ext_tcds2 when "10", + '0' when others; + + -- L1A generation + l1a <= l1a_ttc or l1a_pend; + l1a_issue <= l1a and not l1a_ttc; + + -- TTC command generation + req_bx <= to_unsigned(LHC_BUNCH_COUNT, req_bx'length) - to_unsigned(TTC_DEL, req_bx'length) - 1; + cmd_bx <= '1' when std_logic_vector(req_bx) = bunch_ctr_i else '0'; + + process(cmd_ttc, bc0_fr, cmd_pend, cmd_bx) + begin + cmd_issue <= '0'; + if cmd_ttc /= TTC_BCMD_NULL then + cmd <= cmd_ttc; + elsif bc0_fr = '1' then + cmd <= TTC_BCMD_BC0; + elsif cmd_pend = '1' then + cmd <= ctrl_common(0)(15 downto 8); + cmd_issue <= '1'; + else + cmd <= TTC_BCMD_NULL; + end if; + end process; + + process(clk40_a) + begin + if rising_edge(clk40_a) then + cmd_pend <= (cmd_pend or (ctrl_common(0)(5) and stb_common(0))) and not (rst40_a or cmd_issue); + l1a_pend <= l1a_pend and not (rst40_a or l1a_issue); + ttc_cmd_dist <= cmd; + end if; + end process; + + ttc_l1a_dist <= l1a; + +-- Counters + + ctr_clr <= ctrl_common(0)(4) and stb_common(0); + + ttcctr : entity work.ttc_ctrs + port map( + clk => clk40_a, + rst => rst40_a, + ttc_cmd => cmd, + l1a => l1a, + clr => '0', + en_int_bc0 => ctrl_common(0)(3), + bc0_lock => bc0_lock, + bc0_fr => bc0_fr, + ttc_cmd_out => cmd_del, + l1a_out => l1a_del, + bunch_ctr => bunch_ctr_i, + orb_ctr => orb_ctr_i + ); + + ttc_cmd <= cmd_del; + ttc_l1a <= l1a_del; + bunch_ctr <= bunch_ctr_i; + orb_ctr <= orb_ctr_i; + oc_flag <= '1' when orb_ctr_i(13 downto 0) = (13 downto 0 => '0') and bc0_lock = '1' else '0'; + ec_flag <= '1' when evt_ctr(16 downto 0) = (16 downto 0 => '0') else '0'; + +-- Status reg + + stat_common(0)(7 downto 2) <= (l1a_pend or cmd_pend) & psok & dist_lock & bc0_lock & "00"; + stat_common(0)(19 downto 8) <= bunch_ctr_i; + stat_common(0)(31 downto 20) <= std_logic_vector(to_unsigned(LHC_BUNCH_COUNT, 12)); + stat_common(1) <= evt_ctr; + stat_common(2) <= orb_ctr_i; + +-- clk40 frequency monitoring + + div : entity work.freq_ctr_div + generic map( + N_CLK => 2 + ) + port map( + clk(0) => clk40_a, + clk(1) => tcds_refclk_b, + clkdiv(0) => clk40_div, + clkdiv(1) => tcds_refclk_div + ); + +-- Clock frequency monitor + + ctr : entity work.ipbus_freq_ctr + generic map( + N_CLK => 6 + ) + port map( + clk => clk_ipb, + rst => rst_ipb, + ipb_in => ipbw(N_SLV_FREQ), + ipb_out => ipbr(N_SLV_FREQ), + clkdiv(0) => clk40_div, + clkdiv(1) => tcds_refclk_div, + clkdiv(5 downto 2) => monclk + ); + +-- TTC history buffer + + hist : entity work.ttc_history_new + port map( + clk => clk_ipb, + rst => rst_ipb, + ipb_in => ipbw(N_SLV_HIST), + ipb_out => ipbr(N_SLV_HIST), + ttc_clk => clk40_a, + ttc_rst => rst40_a, + ttc_l1a => l1a_del, + ttc_cmd => cmd_del, + ttc_bx => bunch_ctr_i, + ttc_orb => orb_ctr_i, + ttc_evt => evt_ctr + ); + +-- Command counters + + cmdctrs : entity work.ttc_cmd_ctrs + port map( + clk => clk_ipb, + rst => rst_ipb, + ipb_in => ipbw(N_SLV_CMD_CTRS), + ipb_out => ipbr(N_SLV_CMD_CTRS), + ttc_clk => clk40_a, + clr => ctr_clr, + ttc_cmd => cmd_del + ); + +end rtl; +------------------------------------------------------------------------------- diff --git a/top/firmware/hdl/emp_project_decl.vhd b/top/firmware/hdl/emp_project_decl.vhd index d120be63..b4d2cac9 100644 --- a/top/firmware/hdl/emp_project_decl.vhd +++ b/top/firmware/hdl/emp_project_decl.vhd @@ -23,15 +23,13 @@ package emp_project_decl is constant PAYLOAD_REV : std_logic_vector(31 downto 0) := X"d451d001"; - -- Number of LHC bunches - constant LHC_BUNCH_COUNT : integer := 3564; -- Latency buffer size constant LB_ADDR_WIDTH : integer := 10; -- Clock setup constant CLOCK_COMMON_RATIO : integer := 32; constant CLOCK_RATIO : integer := 8; - constant CLOCK_AUX_RATIO : clock_ratio_array_t := (2, 4, 8); + constant CLOCK_AUX_DIV : clock_divisor_array_t := (16, 8, 4); -- Dividers of CLOCK_COMMON_RATIO * 40 MHz -- Only used by nullalgo constant PAYLOAD_LATENCY : integer := 5; -- GitLab