Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
combpm_protocol_electron.vhd 19.61 KiB

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

use work.pkg_bpmpacket_stream.all;

entity combpm_protocol_electron is
    port(
        rst_n              : in std_logic;                      -- Asynchronous active low reset.
        clk                : in std_logic;                      -- Clock synchronous to data input.
        pps                : in std_logic;                      -- One pulse per second. Used for frame rate estimation.

        mc_time            : in std_logic_vector(39 downto 0);  -- Machine clock time for frame time stamping.

        -- GT interface
        gt_datarx          : in std_logic_vector(15 downto 0);  -- Deserialized data.

        -- AXIS interface
        m_axis_m2s         : out t_bpmpacket_axis_m2s;

        -- Status and control interface
        soft_reset              : in std_logic;                      -- Reset all counters.
        frame_seq_cnt           : out std_logic_vector(15 downto 0); -- Number of frame in last sequence.
        frame_valid_cnt         : out std_logic_vector(31 downto 0); -- Count of valid frames.
        frame_invalid_cnt       : out std_logic_vector(31 downto 0); -- Count of invalid frames.
        frame_valid_rate        : out std_logic_vector(31 downto 0); -- Valid frame rate.
        frame_invalid_rate      : out std_logic_vector(31 downto 0); -- Invalid frame rate.
        flag_cnt_seq_mismatch   : out std_logic;                     -- Number of frame in sequence mismatch.
        flag_seq_discontinuity  : out std_logic;                     -- Discontinuity in sequence number.
        flag_frame_error        : out std_logic;                     -- Frame error.
        flag_reset              : in std_logic                       -- Reset all flags.
    );
end entity combpm_protocol_electron;

architecture rtl of combpm_protocol_electron is

    --------------------------
    -- CONSTANT DECLARATION --
    --------------------------
    constant C_SOP           :  std_logic_vector(15 downto 0) := x"5CFB";
    constant C_EOP           :  std_logic_vector(15 downto 0) := x"FDFE";
    constant C_DUMMY         :  std_logic_vector(31 downto 0) := x"12345678";
    constant C_RSVD          :  std_logic_vector(31 downto 0) := x"00000000";
    constant C_CRCINIT       :  std_logic_vector(31 downto 0) := x"FFFFFFFF";

    ------------------------
    -- SIGNAL DECLARATION --
    ------------------------
    signal packet_reg               :  std_logic_vector(14*16-1 downto 0);   -- Register to hold one packet

    signal flag_sop_inc             :  std_logic;
    signal flag_sop                 :  std_logic;
    signal flag_eop                 :  std_logic;
    signal flag_dummy               :  std_logic;
    signal flag_rsvd                :  std_logic;
    signal flag_crc                 :  std_logic;
    signal flag_all                 :  std_logic;
    signal flag_frame               :  std_logic;

    signal packet_bpmid             :  std_logic_vector(9 downto 0);
    signal packet_startframe        :  std_logic;
    signal packet_timestamp         :  std_logic_vector(15 downto 0);
    signal packet_xpos              :  std_logic_vector(31 downto 0);
    signal packet_ypos              :  std_logic_vector(31 downto 0);
    signal packet_crc               :  std_logic_vector(31 downto 0);

    signal crc_result               :  std_logic_vector(31 downto 0);
    signal xorinv_crc_reg           :  std_logic_vector(31 downto 0);
    signal inv_crc_reg              :  std_logic_vector(31 downto 0);
    signal crc_reg                  :  std_logic_vector(31 downto 0);
    signal lfsr_c                   :  std_logic_vector(31 downto 0);
    signal crc_cnt                  :  unsigned(3 downto 0);
    signal d                        :  std_logic_vector(15 downto 0);

    signal last_seq                 :  std_logic_vector(15 downto 0);

    signal last_cnt_seq_r           :  unsigned(15 downto 0);
    signal cnt_frame_seq_r          :  unsigned(15 downto 0);
    signal cnt_valid_r              :  unsigned(31 downto 0);
    signal cnt_invalid_r            :  unsigned(31 downto 0);
    signal rate_valid_r             :  unsigned(31 downto 0);
    signal rate_invalid_r           :  unsigned(31 downto 0);

    signal packet                   : t_bpmpacket;
    signal m_axi_tvalid             : std_logic;

    signal cnt_seq_mismatch         : std_logic;
    signal seq_discontinuity        : std_logic;
    signal frame_error              : std_logic;


begin


    ------------------------
    -- STICKY ERROR FLAGS --
    ------------------------
    p_stickerr:process(clk, rst_n)
    begin
        if rst_n = '0' then
            flag_cnt_seq_mismatch           <= '0';
            flag_seq_discontinuity          <= '0';
            flag_frame_error                <= '0';
        elsif rising_edge(clk) then

            if flag_reset = '1' then
                flag_cnt_seq_mismatch       <= '0';
                flag_seq_discontinuity      <= '0';
                flag_frame_error            <= '0';
            else
                if cnt_seq_mismatch = '1' then
                    flag_cnt_seq_mismatch   <= '1';
                end if;
                if seq_discontinuity = '1' then
                    flag_seq_discontinuity  <= '1';
                end if;
                if frame_error = '1' then
                    flag_frame_error        <= '1';
                end if;
            end if;
        end if;
    end process;


    ---------------------
    -- PACKET REGISTER --
    ---------------------
    p_packetreg:process(clk, rst_n)
    begin
        if rst_n = '0' then
            packet_reg <= (others => '0');
        elsif rising_edge(clk) then
            -- Simple shift register, 16 bits width, 14 word long
            for I in 2 to 14 loop
                packet_reg(I*16-1 downto (I-1)*16) <= packet_reg((I-1)*16-1 downto (I-2)*16);
            end loop;

            -- swap bytes in input (first byte is LSB)
            packet_reg(15 downto 0)  <= gt_datarx(7 downto 0) & gt_datarx(15 downto 8);
        end if;
    end process;

    ------------------------
    -- PACKET CHECK FLAGS --
    ------------------------
    flag_sop            <= '1' when packet_reg(14*16-1 downto 13*16) = C_SOP else
                           '0';

    flag_sop_inc        <= '1' when packet_reg(15 downto 0) = C_SOP else
                           '0';

    flag_eop            <= '1' when packet_reg(15 downto 0) = C_EOP else
                            '0';

    flag_dummy          <= '1' when packet_reg(7*16-1 downto 5*16) = C_DUMMY else
                           '0';

    flag_rsvd           <= '1' when packet_reg(5*16-1 downto 3*16) = C_RSVD else
                           '0';

    flag_crc            <= '1' when packet_crc = crc_result else
                           '0';

    -- Any and all flag
    flag_all            <= flag_sop and flag_eop and flag_crc;
    flag_frame          <= flag_sop and flag_eop;

    ----------------------------
    -- FRAME FIELD EXTRACTION --
    ----------------------------
    packet_bpmid      <= packet_reg(185 downto 176);

    packet_startframe <= packet_reg(191);

    packet_timestamp  <= packet_reg(13*16-1 downto 12*16);

    packet_xpos       <= packet_reg(11*16-1 downto 9*16);
    packet_ypos       <= packet_reg(9*16-1 downto 7*16);

    packet_crc        <= packet_reg(3*16-1 downto 16);

    -----------------
    -- CRC CHECKER --
    -----------------

    -- RefIn
    gen_invert: for I in 0 to 7 generate
        d(I)    <= packet_reg(7-I);
        d(I+8)  <= packet_reg(7-I+8);
    end generate;


    -- RefOut
    xorinv_crc_reg <= inv_crc_reg xor x"FFFFFFFF";
    gen: for I in 0 to 31 generate
        inv_crc_reg(I) <= crc_reg(31-I);
    end generate;

    -- Byte reorder
    crc_result(7 downto 0)   <= xorinv_crc_reg(31 downto 24);
    crc_result(15 downto 8)  <= xorinv_crc_reg(23 downto 16);
    crc_result(23 downto 16) <= xorinv_crc_reg(15 downto 8);
    crc_result(31 downto 24) <= xorinv_crc_reg(7 downto 0);

    -- Register
    p_crc:process(clk, rst_n)
    begin
        if rst_n = '0' then
            crc_reg <= C_CRCINIT;
            crc_cnt <= (others => '0');
        elsif rising_edge(clk) then
            case crc_cnt is
                when "0000" =>
                    if flag_sop_inc = '1' then
                        crc_cnt <= crc_cnt+1;
                        crc_reg <= C_CRCINIT;
                    else
                        crc_cnt <= (others => '0');
                    end if;
                when "1011" =>
                    crc_reg <= crc_reg;
                    crc_cnt <= crc_cnt+1;
                when "1100" =>
                    crc_reg <= crc_reg;
                    crc_cnt <= (others => '0');
                when others =>
                    crc_reg <= lfsr_c;
                    crc_cnt <= crc_cnt+1;
            end case;

        end if;
    end process p_crc;

    -- Combinatorial, 16 turns unrolled
    lfsr_c(0) <= crc_reg(16) xor crc_reg(22) xor crc_reg(25) xor crc_reg(26) xor crc_reg(28) xor d(0) xor d(6) xor d(9) xor d(10) xor d(12);
    lfsr_c(1) <= crc_reg(16) xor crc_reg(17) xor crc_reg(22) xor crc_reg(23) xor crc_reg(25) xor crc_reg(27) xor crc_reg(28) xor crc_reg(29) xor d(0) xor d(1) xor d(6) xor d(7) xor d(9) xor d(11) xor d(12) xor d(13);
    lfsr_c(2) <= crc_reg(16) xor crc_reg(17) xor crc_reg(18) xor crc_reg(22) xor crc_reg(23) xor crc_reg(24) xor crc_reg(25) xor crc_reg(29) xor crc_reg(30) xor d(0) xor d(1) xor d(2) xor d(6) xor d(7) xor d(8) xor d(9) xor d(13) xor d(14);
    lfsr_c(3) <= crc_reg(17) xor crc_reg(18) xor crc_reg(19) xor crc_reg(23) xor crc_reg(24) xor crc_reg(25) xor crc_reg(26) xor crc_reg(30) xor crc_reg(31) xor d(1) xor d(2) xor d(3) xor d(7) xor d(8) xor d(9) xor d(10) xor d(14) xor d(15);
    lfsr_c(4) <= crc_reg(16) xor crc_reg(18) xor crc_reg(19) xor crc_reg(20) xor crc_reg(22) xor crc_reg(24) xor crc_reg(27) xor crc_reg(28) xor crc_reg(31) xor d(0) xor d(2) xor d(3) xor d(4) xor d(6) xor d(8) xor d(11) xor d(12) xor d(15);
    lfsr_c(5) <= crc_reg(16) xor crc_reg(17) xor crc_reg(19) xor crc_reg(20) xor crc_reg(21) xor crc_reg(22) xor crc_reg(23) xor crc_reg(26) xor crc_reg(29) xor d(0) xor d(1) xor d(3) xor d(4) xor d(5) xor d(6) xor d(7) xor d(10) xor d(13);
    lfsr_c(6) <= crc_reg(17) xor crc_reg(18) xor crc_reg(20) xor crc_reg(21) xor crc_reg(22) xor crc_reg(23) xor crc_reg(24) xor crc_reg(27) xor crc_reg(30) xor d(1) xor d(2) xor d(4) xor d(5) xor d(6) xor d(7) xor d(8) xor d(11) xor d(14);
    lfsr_c(7) <= crc_reg(16) xor crc_reg(18) xor crc_reg(19) xor crc_reg(21) xor crc_reg(23) xor crc_reg(24) xor crc_reg(26) xor crc_reg(31) xor d(0) xor d(2) xor d(3) xor d(5) xor d(7) xor d(8) xor d(10) xor d(15);
    lfsr_c(8) <= crc_reg(16) xor crc_reg(17) xor crc_reg(19) xor crc_reg(20) xor crc_reg(24) xor crc_reg(26) xor crc_reg(27) xor crc_reg(28) xor d(0) xor d(1) xor d(3) xor d(4) xor d(8) xor d(10) xor d(11) xor d(12);
    lfsr_c(9) <= crc_reg(17) xor crc_reg(18) xor crc_reg(20) xor crc_reg(21) xor crc_reg(25) xor crc_reg(27) xor crc_reg(28) xor crc_reg(29) xor d(1) xor d(2) xor d(4) xor d(5) xor d(9) xor d(11) xor d(12) xor d(13);
    lfsr_c(10) <= crc_reg(16) xor crc_reg(18) xor crc_reg(19) xor crc_reg(21) xor crc_reg(25) xor crc_reg(29) xor crc_reg(30) xor d(0) xor d(2) xor d(3) xor d(5) xor d(9) xor d(13) xor d(14);
    lfsr_c(11) <= crc_reg(16) xor crc_reg(17) xor crc_reg(19) xor crc_reg(20) xor crc_reg(25) xor crc_reg(28) xor crc_reg(30) xor crc_reg(31) xor d(0) xor d(1) xor d(3) xor d(4) xor d(9) xor d(12) xor d(14) xor d(15);
    lfsr_c(12) <= crc_reg(16) xor crc_reg(17) xor crc_reg(18) xor crc_reg(20) xor crc_reg(21) xor crc_reg(22) xor crc_reg(25) xor crc_reg(28) xor crc_reg(29) xor crc_reg(31) xor d(0) xor d(1) xor d(2) xor d(4) xor d(5) xor d(6) xor d(9) xor d(12) xor d(13) xor d(15);
    lfsr_c(13) <= crc_reg(17) xor crc_reg(18) xor crc_reg(19) xor crc_reg(21) xor crc_reg(22) xor crc_reg(23) xor crc_reg(26) xor crc_reg(29) xor crc_reg(30) xor d(1) xor d(2) xor d(3) xor d(5) xor d(6) xor d(7) xor d(10) xor d(13) xor d(14);
    lfsr_c(14) <= crc_reg(18) xor crc_reg(19) xor crc_reg(20) xor crc_reg(22) xor crc_reg(23) xor crc_reg(24) xor crc_reg(27) xor crc_reg(30) xor crc_reg(31) xor d(2) xor d(3) xor d(4) xor d(6) xor d(7) xor d(8) xor d(11) xor d(14) xor d(15);
    lfsr_c(15) <= crc_reg(19) xor crc_reg(20) xor crc_reg(21) xor crc_reg(23) xor crc_reg(24) xor crc_reg(25) xor crc_reg(28) xor crc_reg(31) xor d(3) xor d(4) xor d(5) xor d(7) xor d(8) xor d(9) xor d(12) xor d(15);
    lfsr_c(16) <= crc_reg(0) xor crc_reg(16) xor crc_reg(20) xor crc_reg(21) xor crc_reg(24) xor crc_reg(28) xor crc_reg(29) xor d(0) xor d(4) xor d(5) xor d(8) xor d(12) xor d(13);
    lfsr_c(17) <= crc_reg(1) xor crc_reg(17) xor crc_reg(21) xor crc_reg(22) xor crc_reg(25) xor crc_reg(29) xor crc_reg(30) xor d(1) xor d(5) xor d(6) xor d(9) xor d(13) xor d(14);
    lfsr_c(18) <= crc_reg(2) xor crc_reg(18) xor crc_reg(22) xor crc_reg(23) xor crc_reg(26) xor crc_reg(30) xor crc_reg(31) xor d(2) xor d(6) xor d(7) xor d(10) xor d(14) xor d(15);
    lfsr_c(19) <= crc_reg(3) xor crc_reg(19) xor crc_reg(23) xor crc_reg(24) xor crc_reg(27) xor crc_reg(31) xor d(3) xor d(7) xor d(8) xor d(11) xor d(15);
    lfsr_c(20) <= crc_reg(4) xor crc_reg(20) xor crc_reg(24) xor crc_reg(25) xor crc_reg(28) xor d(4) xor d(8) xor d(9) xor d(12);
    lfsr_c(21) <= crc_reg(5) xor crc_reg(21) xor crc_reg(25) xor crc_reg(26) xor crc_reg(29) xor d(5) xor d(9) xor d(10) xor d(13);
    lfsr_c(22) <= crc_reg(6) xor crc_reg(16) xor crc_reg(25) xor crc_reg(27) xor crc_reg(28) xor crc_reg(30) xor d(0) xor d(9) xor d(11) xor d(12) xor d(14);
    lfsr_c(23) <= crc_reg(7) xor crc_reg(16) xor crc_reg(17) xor crc_reg(22) xor crc_reg(25) xor crc_reg(29) xor crc_reg(31) xor d(0) xor d(1) xor d(6) xor d(9) xor d(13) xor d(15);
    lfsr_c(24) <= crc_reg(8) xor crc_reg(17) xor crc_reg(18) xor crc_reg(23) xor crc_reg(26) xor crc_reg(30) xor d(1) xor d(2) xor d(7) xor d(10) xor d(14);
    lfsr_c(25) <= crc_reg(9) xor crc_reg(18) xor crc_reg(19) xor crc_reg(24) xor crc_reg(27) xor crc_reg(31) xor d(2) xor d(3) xor d(8) xor d(11) xor d(15);
    lfsr_c(26) <= crc_reg(10) xor crc_reg(16) xor crc_reg(19) xor crc_reg(20) xor crc_reg(22) xor crc_reg(26) xor d(0) xor d(3) xor d(4) xor d(6) xor d(10);
    lfsr_c(27) <= crc_reg(11) xor crc_reg(17) xor crc_reg(20) xor crc_reg(21) xor crc_reg(23) xor crc_reg(27) xor d(1) xor d(4) xor d(5) xor d(7) xor d(11);
    lfsr_c(28) <= crc_reg(12) xor crc_reg(18) xor crc_reg(21) xor crc_reg(22) xor crc_reg(24) xor crc_reg(28) xor d(2) xor d(5) xor d(6) xor d(8) xor d(12);
    lfsr_c(29) <= crc_reg(13) xor crc_reg(19) xor crc_reg(22) xor crc_reg(23) xor crc_reg(25) xor crc_reg(29) xor d(3) xor d(6) xor d(7) xor d(9) xor d(13);
    lfsr_c(30) <= crc_reg(14) xor crc_reg(20) xor crc_reg(23) xor crc_reg(24) xor crc_reg(26) xor crc_reg(30) xor d(4) xor d(7) xor d(8) xor d(10) xor d(14);
    lfsr_c(31) <= crc_reg(15) xor crc_reg(21) xor crc_reg(24) xor crc_reg(25) xor crc_reg(27) xor crc_reg(31) xor d(5) xor d(8) xor d(9) xor d(11) xor d(15);


    --------------
    -- AXIS OUT --
    --------------
    m_axis_m2s.tdest    <= (others => '0');
    m_axis_m2s.tdata    <= bpmpacket2slv(packet);
    m_axis_m2s.tlast    <= '1'; -- One transfer is One packet.
    m_axis_m2s.tvalid   <= m_axi_tvalid;


    p_axis:process(clk, rst_n)
    begin
        if rst_n = '0' then
            packet  <= C_BPMPACKET_ZERO;
            m_axi_tvalid <= '0';

        elsif rising_edge(clk) then

            if flag_all = '1' then
                -- Make AXIS packet
                packet.pos_x        <= packet_xpos;
                packet.pos_y        <= packet_ypos;
                packet.bpm_id       <= "000000" & packet_bpmid;
                packet.mc_timestamp <= mc_time;
                packet.fa_seq       <= packet_timestamp(7 downto 0);

                -- AXIS TVALID
                m_axi_tvalid            <= not soft_reset;
            else
                m_axi_tvalid            <= '0';
            end if;
        end if;
    end process p_axis;

    ------------------------
    -- CONTROL AND STATUS --
    ------------------------
    frame_error         <= flag_frame and not flag_all;
    frame_valid_cnt     <= std_logic_vector(cnt_valid_r);
    frame_invalid_cnt   <= std_logic_vector(cnt_invalid_r);
    frame_seq_cnt       <= std_logic_vector(last_cnt_seq_r);

    -- frame counter
    p_framecnt:process(clk, rst_n)
    begin
        if rst_n = '0' then
            cnt_frame_seq_r <= (others => '0');
            cnt_valid_r     <= (others => '0');
            cnt_invalid_r   <= (others => '0');
            rate_valid_r    <= (others => '0');
            rate_invalid_r  <= (others => '0');
            frame_valid_rate<= (others => '0');
            frame_invalid_rate<= (others => '0');
            last_seq        <= (others => '0');
            last_cnt_seq_r  <= (others => '0');
            seq_discontinuity <= '0';
            cnt_seq_mismatch    <= '0';
        elsif rising_edge(clk) then

            if soft_reset = '1' then
                cnt_frame_seq_r <= (others => '0');
                cnt_valid_r     <= (others => '0');
                cnt_invalid_r   <= (others => '0');
                rate_valid_r    <= (others => '0');
                rate_invalid_r  <= (others => '0');
                frame_valid_rate<= (others => '0');
                frame_invalid_rate<= (others => '0');
                last_seq        <= (others => '0');
                last_cnt_seq_r  <= (others => '0');
                seq_discontinuity <= '0';
                cnt_seq_mismatch    <= '0';
            else
                -- Valid frame counter
                if flag_all = '1' then
                    cnt_valid_r <= cnt_valid_r+1;
                end if;

                -- Invalid frame counter
                if (flag_frame and not flag_all) = '1' then
                    cnt_invalid_r <= cnt_invalid_r+1;
                end if;
                -- Rate counter
                if pps = '1' then
                    frame_valid_rate     <= std_logic_vector(rate_valid_r);
                    frame_invalid_rate   <= std_logic_vector(rate_invalid_r);
                    rate_valid_r    <= (others => '0');
                    rate_invalid_r  <= (others => '0');
                else
                    -- Valid frame rate counter
                    if flag_all = '1' then
                        rate_valid_r <= rate_valid_r+1;
                    end if;

                    -- Invalid frame rate counter
                    if (flag_frame and not flag_all) = '1' then
                        rate_invalid_r <= rate_invalid_r+1;
                    end if;
                end if;

                -- Sequence detection
                cnt_seq_mismatch    <= '0'; -- Supercharged in logic below
                seq_discontinuity   <= '0'; -- Supercharged in logic below
                if flag_all = '1' then
                    if last_seq  = packet_timestamp then
                        -- Same sequence
                        cnt_frame_seq_r  <= cnt_frame_seq_r+1;
                    else
                        -- New sequence
                        cnt_frame_seq_r <= (others => '0');
                        last_seq        <= packet_timestamp;
                        last_cnt_seq_r  <= cnt_frame_seq_r;

                        -- Check sequence increment
                        if unsigned(packet_timestamp) - unsigned(last_seq) /= 1 then
                            seq_discontinuity   <= '1';
                        end if;

                        -- Check number of frame in sequence
                        if last_cnt_seq_r /= cnt_frame_seq_r then
                            cnt_seq_mismatch <= '1';
                        end if;
                    end if;
                end if;

            end if;
        end if;
    end process p_framecnt;

end architecture rtl;