SERENITY HOME EMP Framework Guide Logo
FW 0.9.3 / SW 0.9.4
  • The basic idea
  • Walkthroughs for First Users
  • EMP firmware
    • Firmware: Build and simulation instructions
      • Prerequisites
        • Build tool
        • Vivado
      • Step 1: Setup your IPBB area
      • Step 2: Add the payload repository
      • Step 3: Build firmware or run simulation
    • Payload firmware: Interface
      • emp_payload entity
      • emp_project_decl package
      • tb_decl package
    • Backend links
      • CSP protocol in a nutshell
      • Payload port specification
      • Example use cases
        • TM6 link with back-to-back packets
        • TM18 link with gap between packets
  • EMP software
    • Installation
      • YUM repositories
      • Compiling from source
        • Part 1: Prerequisites
        • Part 2: EMP toolbox
    • Standard workflows
      • Testing payload firmware in a single FPGA
      • Configuring and monitoring link firmware
        • Loopback
        • Board-to-board tests
      • Bathtub and eye scans
        • Python dependencies
        • Links yaml file
        • Scanning the links
        • Standalone plotting
    • EMP butler: Reference guide
      • Top-level interface
    • Butler scripting interface
      • Example: Link loopback pattern test
    • Buffer data files
      • Format
      • Example
    • Testing the firmware and software
      • Environment
      • Running the test suite
  • Reference bitfiles
  • Release notes
    • Software
      • Version 0.9.4
      • Version 0.9.3
      • Version 0.9.2
      • Version 0.9.1
      • Version 0.9.0
      • Version 0.8.4
      • Version 0.8.3
      • Version 0.8.2
      • Version 0.8.1
      • Version 0.8.0
      • Version 0.7.6
      • Version 0.7.5
      • Version 0.7.4
      • Version 0.7.3
      • Version 0.7.2
      • Version 0.7.1
      • Version 0.7.0
      • Version 0.6.8
      • Version 0.6.7
      • Version 0.6.6
      • Version 0.6.5
      • Version 0.6.4
      • Version 0.6.3
      • Version 0.6.2
      • Version 0.6.1
      • Version 0.6.0
      • Version 0.5.4
      • Version 0.5.3
      • Version 0.5.2
      • Version 0.5.1
      • Version 0.5.0
      • Version 0.4.6
      • Version 0.4.5
      • Version 0.4.4
      • Version 0.4.3
      • Version 0.4.2
      • Version 0.4.1
      • Version 0.4.0
      • Version 0.3.7
      • Version 0.3.6
      • Version 0.3.5
      • Version 0.3.4
      • Version 0.3.3
      • Version 0.3.2
      • Version 0.3.1
      • Version 0.3.0
      • Version 0.2.8
      • Version 0.2.7
      • Version 0.2.6
      • Version 0.2.5
      • Version 0.2.4
      • Version 0.2.3
      • Version 0.2.2
      • Version 0.2.1
      • Version 0.2.0
      • Version 0.1.0
    • Firmware
      • Version 0.9.3
      • Version 0.9.2
      • Version 0.9.1
      • Version 0.9.0
        • Migration guide: 0.8.x to 0.9.0
      • Version 0.8.2
      • Version 0.8.1
      • Version 0.8.0
      • Version 0.7.5
      • Version 0.7.4
      • Version 0.7.3
      • Version 0.7.2
      • Version 0.7.1
      • Version 0.7.0
        • Migration guide: 0.6.x to 0.7.0
      • Version 0.7.0, alpha pre-release
      • Version 0.6.8
      • Version 0.6.7
      • Version 0.6.6
      • Version 0.6.5
      • Version 0.6.4
      • Version 0.6.3
      • Version 0.6.2
      • Version 0.6.1
      • Version 0.6.0
        • Migration guide: 0.5.x to 0.6.0
      • Version 0.5.8
      • Version 0.5.7
      • Version 0.5.6
      • Version 0.5.5
      • Version 0.5.4
      • Version 0.5.3
      • Version 0.5.2
      • Version 0.5.1
      • Version 0.5.0
      • Version 0.3.6
      • Version 0.3.5
      • Version 0.3.4
      • Version 0.3.3
      • Version 0.3.2
      • Version 0.3.1
      • Version 0.3.0
      • Version 0.2.5
      • Version 0.2.4
      • Version 0.2.3
      • Version 0.2.2
      • Version 0.2.1
      • Version 0.2.0
      • Version 0.1.2
      • Version 0.1.1
      • Version 0.1.0
Licence
EMP Framework Guide
  • Docs »
  • EMP firmware »
  • Backend links

Backend links¶

Since version 0.7.0, the EMP firmware framework implements the CMS standard trigger link protocol (CSP) for links that transmit data between backend boards with low, fixed latency. This page describes the meaning of the fields in the payload’s d and q ports for I/O channels connected to the backend link engine, how they should be used, and gives some related examples.

CSP protocol in a nutshell¶

The CSP protocol is used to transmit LHC-synchronous data over asynchronous links between backend boards. The throughput of the asynchronous links we use is slightly larger than that required for the LHC-syncronous data transmission, and so the spare bandwidth is used to ensure robustness and to carry link metadata. For 25G links, an EMP payload transmits/receives nine 64-bit words per LHC clock cycle (i.e. payload frequency is 360.xxMHz); for 16G links, an EMP payload transmits/receives six 64-bit words per LHC clock cycloe (i.e. payload frequency is 240.xxMHz).

There are two types of words on the link itself (i.e. after CSP encoding):

  • Data words, carrying the LHC-sychronous data from/to payload firmware; and

  • Filler words, added to reach the line rates

From the perspective of the payload firmware data is organised in packets, which are contiguous groups of data words. A CRC is calculated for each packet by the CSP transmitter firmware and sent in a filler word following the packet. The CRC is also calculated by the CSP transmitter firmware, and the number of mismatches - indicating bitflips in data words - are stored in one of the status registers. For links with time multiplexing period greater than 1, all the data contained in each packet should be associated with the same collision. Due to the small filler-to-data word ratio on a fully-utilised link, for a time multiplexing period of 1, data from two or three collisions must be transmitted in a single packet. If there are gaps of multiple clock cycles between subsequent packets, then additional filler words referred to as idle words are transmitted on the link inbetween the packets, in place of data words.

Payload port specification¶

For backend link channels, the meaning of the ldata fields in the payload’s d and q ports are as follows:

valid

Distinguishes data within packets vs the idle words sent between packets. Asserted on the first clock cycle in each packet until the last clock cycle in the packet. Remains high constantly when back-to-back packets are transmitted

start

Asserted on first clock cycle in each packet.

last

Asserted on last clock cycle in each packet.

start_of_orbit

Asserted on the first clock cycle of the first packet of the orbit – i.e. the packet that contains data from BXn < M, where M is the TMUX period (e.g. the packet containing BX0 data on links in timeslace 0, the packet containing BX1 data on links in timeslice 1).

data

64-bit word of payload data received/transmitted inside packets. Undefined for clock cycles inbetween packets (when valid is low).

The strobe signal should currently always be asserted for backend links.

Example use cases¶

TM6 link with back-to-back packets¶

The diagram below shows the port values for a TM6 25G link carrying back-to-back packets (hence packets are 6 x 9 = 54 clock cycles in length):

../_images/wavedrom-a0e61998-4a9f-468b-be41-7330bf692fbf.svg

TM18 link with gap between packets¶

The diagram below shows the port values for a TM18 25G link with a gap of 6 clock cycles between packets (hence packets are 18 x 9 - 6 = 156 clock cycles in length):

../_images/wavedrom-f677cfdf-3cbb-48bf-8e64-a43a37ed0b76.svg

The following example payload entity implements this packet structure - with the data word set to a counter pattern composed from the channel index, packet index, and word index:

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;

use work.ipbus.all;
use work.emp_data_types.all;
use work.emp_project_decl.all;

use work.emp_device_decl.all;
use work.emp_ttc_decl.all;

use work.emp_slink_types.all;

entity emp_payload is
  port(
    clk         : in  std_logic;        -- ipbus signals
    rst         : in  std_logic;
    ipb_in      : in  ipb_wbus;
    ipb_out     : out ipb_rbus;
    clk40       : in  std_logic;
    clk_payload : in  std_logic_vector(2 downto 0);
    rst_payload : in  std_logic_vector(2 downto 0);
    clk_p       : in  std_logic;        -- data clock
    rst_loc     : in  std_logic_vector(N_REGION - 1 downto 0);
    clken_loc   : in  std_logic_vector(N_REGION - 1 downto 0);
    ctrs        : in  ttc_stuff_array;
    bc0         : out std_logic;
    d           : in  ldata(4 * N_REGION - 1 downto 0);  -- data in
    q           : out ldata(4 * N_REGION - 1 downto 0);  -- data out
    gpio        : out std_logic_vector(29 downto 0);  -- IO to mezzanine connector
    gpio_en     : out std_logic_vector(29 downto 0);  -- IO to mezzanine connector (three-state enables)
    slink_q : out slink_input_data_quad_array(SLINK_MAX_QUADS-1 downto 0);
    backpressure : in std_logic_vector(SLINK_MAX_QUADS-1 downto 0)
    );

end emp_payload;

architecture rtl of emp_payload is

begin

  -- This example code sends 156-word-long TMUX18 packets (i.e. same packet length as track finder output)
  -- with channel index, packet index, and word index embedded in the data word
  gen : for i in N_REGION * 4 - 1 downto 0 generate

    -- Index of word within a packet
    signal word_index : std_logic_vector(7 downto 0) := x"00";
    -- Index of packet within an orbit
    signal packet_index : std_logic_vector(8 downto 0) := "000000000";

  begin

    process (clk_p)
    begin
      if rising_edge(clk_p) then
        -- Reset counters on receiving BC0 from TCDS
        if (ctrs(i/4).bctr = x"000") and (ctrs(i/4).pctr = "0000") then
          word_index <= x"00";
          packet_index <= "000000000";
        -- Reset word index and increment packet index every 162 clock cycles (TMUX18: 18BX * 9 clocks/BX)
        elsif word_index = x"A1" then
          word_index <= x"00";
          packet_index <= std_logic_vector(unsigned(packet_index) + 1);
        else
          word_index <= std_logic_vector(unsigned(word_index) + 1);
        end if;
      end if;
    end process;

    -- Set valid high for full duration of packet
    q(i).valid <= '1' when word_index <= x"9B" else '0';
    -- Start & last are only high for first & last clock cycle of packet
    q(i).start <= '1' when word_index = x"00" else '0';
    q(i).last <= '1' when word_index = x"9B" else '0';

    -- Start of orbit is high in the first clock cycle of the first packet in orbit - though in final system this should instead
    -- be high in the first clock cycle of the packet containing the data from BX0 (or BXn in time slice n of a TMUX system)
    q(i).start_of_orbit <= '1' when ((word_index = x"00") and (packet_index = "000000000")) else '0';

    -- Data word: Bits 63 to 32 = channel index; bits 31 to 16 = packet index; bits 15 to 0 = word index.
    q(i).data(63 downto 32) <= std_logic_vector(to_unsigned(i, 32));
    q(i).data(31 downto 16) <= "0000000" & packet_index;
    q(i).data(15 downto 0) <= x"00" & word_index;

  end generate gen;

end rtl;
Next Previous

© Copyright 2019, EMP Collaboration.