From d585ad88a67a8016bd4b4c1ac863b8003aeb5c26 Mon Sep 17 00:00:00 2001 From: Benedikt Gutsche Date: Wed, 10 Jan 2024 11:30:46 +0100 Subject: [PATCH] added GBT stuff --- vldb/code/GBT-SC/IC/ic_deserializer.vhd | 147 +++ vldb/code/GBT-SC/IC/ic_rx.vhd | 156 +++ vldb/code/GBT-SC/IC/ic_rx_fifo.vhd | 114 +++ vldb/code/GBT-SC/IC/ic_top.vhd | 234 +++++ vldb/code/GBT-SC/IC/ic_tx.vhd | 1057 +++++++++++++++++++++ vldb/code/GBT-SC/SCA/sca_deserializer.vhd | 148 +++ vldb/code/GBT-SC/SCA/sca_pkg.vhd | 111 +++ vldb/code/GBT-SC/SCA/sca_rx.vhd | 203 ++++ vldb/code/GBT-SC/SCA/sca_rx_fifo.vhd | 108 +++ vldb/code/GBT-SC/SCA/sca_top.vhd | 231 +++++ vldb/code/GBT-SC/SCA/sca_tx.vhd | 537 +++++++++++ vldb/code/GBT-SC/gbtsc_top.vhd | 301 ++++++ vldb/code/gbt_core.vhd | 265 ++++++ 13 files changed, 3612 insertions(+) create mode 100644 vldb/code/GBT-SC/IC/ic_deserializer.vhd create mode 100644 vldb/code/GBT-SC/IC/ic_rx.vhd create mode 100644 vldb/code/GBT-SC/IC/ic_rx_fifo.vhd create mode 100644 vldb/code/GBT-SC/IC/ic_top.vhd create mode 100644 vldb/code/GBT-SC/IC/ic_tx.vhd create mode 100644 vldb/code/GBT-SC/SCA/sca_deserializer.vhd create mode 100644 vldb/code/GBT-SC/SCA/sca_pkg.vhd create mode 100644 vldb/code/GBT-SC/SCA/sca_rx.vhd create mode 100644 vldb/code/GBT-SC/SCA/sca_rx_fifo.vhd create mode 100644 vldb/code/GBT-SC/SCA/sca_top.vhd create mode 100644 vldb/code/GBT-SC/SCA/sca_tx.vhd create mode 100644 vldb/code/GBT-SC/gbtsc_top.vhd create mode 100644 vldb/code/gbt_core.vhd diff --git a/vldb/code/GBT-SC/IC/ic_deserializer.vhd b/vldb/code/GBT-SC/IC/ic_deserializer.vhd new file mode 100644 index 0000000..62949f5 --- /dev/null +++ b/vldb/code/GBT-SC/IC/ic_deserializer.vhd @@ -0,0 +1,147 @@ +------------------------------------------------------- +--! @file +--! @author Julian Mendez (CERN - EP-ESE-BE) +--! @date April, 2017 +--! @version 1.0 +--! @brief IC control - IC Field deserializer/decoder +------------------------------------------------------- + +--! Include the IEEE VHDL standard library +library ieee; +--! Use STD_Logic to define vector types +use ieee.std_logic_1164.all; +--! Used to convert std_logic_vector to integer and manage fifo pointer +use ieee.numeric_std.all; + +--! @brief IC_Deserializer Entity - IC Field deserializer/decoder +--! @details +--! The IC_Deserializer deserializes the data and removes the zeros +--! inserted as specified by the HDLC standard (bit stuffing). +--! Additionally, it detects the delimiter pattern to inform the +--! core when a new frame is received. +entity ic_deserializer is + generic ( + g_WORD_SIZE : integer := 8; --! Size of the words to be stored + g_DELIMITER : std_logic_vector(7 downto 0) := "01111110" --! Delimiter pattern, defined by the HDLC standard ("01111110") + ); + port ( + clk_i : in std_logic; --! Rx clock (Rx_frameclk_o from GBT-FPGA IP): must be a multiple of the LHC frequency + rx_clk_en : in std_logic; --! Rx clock enable signal must be used in case of multi-cycle path(rx_clk_i > LHC frequency). By default: always enabled + + reset_i : in std_logic; --! Reset all of the RX processes + + -- Data + data_i : in std_logic_vector(1 downto 0); --! (RX) Array of bits from the GBT-Frame (bits 83/84) - IC line + data_o : out std_logic_vector((g_WORD_SIZE-1) downto 0); --! Deserialized/decoded data + + -- Status + write_o : out std_logic; --! Write signal to the FIFO + new_word_o : out std_logic --! New frame received (Delimiter detected) + ); +end ic_deserializer; + +--! @brief IC_Deserializer Architecture - IC Field deserializer/decoder +--! @details +--! The IC_Deserializer architecture describes the logic required to +--! deserialize the input and decode the "HDLC" frame. The decoding +--! consists in removing the '0' inserted every 5 consecutive high level bits +--! bits and detecting/removing the delimiter packets (SOF/EOF). +architecture behaviour of ic_deserializer is +begin --========#### Architecture Body ####========-- + + --! @brief Deserializer process: manages the decoding/deserialization + --! @details + --! The deserialization is based on a counter, used to control the write_o + --! signal (set to '1' when cnter value >= to the word size). The counter + --! is reseted when a delimiter is received to synchronize the system and + --! incremented when a valid bit is received (not a '0' to be removed). + --! Finally, because of the size of the serial frame (2 bits and not only one), + --! the logic of the process is duplicated once. + --! An on-going signal is used to know wether the delimiter packet received + --! is a start or end of frame. + deserializer: process(reset_i, clk_i) + + variable reg : std_logic_vector(g_WORD_SIZE-1 downto 0); + variable reg_no_destuffing : std_logic_vector(g_WORD_SIZE-1 downto 0); + variable cnter : integer range 0 to g_WORD_SIZE; + variable ongoing : std_logic; + + begin + + if reset_i = '1' then + cnter := 0; + reg := (others => '0'); + reg_no_destuffing := (others => '0'); + ongoing := '0'; + + elsif rising_edge(clk_i) then + + if rx_clk_en = '1' then + write_o <= '0'; + new_word_o <= '0'; + + -- Data(1) + reg(7 downto 0) := data_i(1) & reg(7 downto 1); + reg_no_destuffing := data_i(1) & reg_no_destuffing(7 downto 1); + + if reg_no_destuffing(7 downto 1) = "0111110" then + reg(7 downto 0) := reg(6 downto 0) & '0'; + + elsif ongoing = '1' then + cnter := cnter + 1; + + end if; + + if reg_no_destuffing = g_DELIMITER then + cnter := 0; + ongoing := '1'; + new_word_o <= '1'; + + elsif reg_no_destuffing = x"FF" then + ongoing := '0'; + + end if; + + if cnter >= g_WORD_SIZE and ongoing = '1' then + cnter := 0; + data_o <= reg; + write_o <= '1'; + end if; + + -- Data(0) + reg(7 downto 0) := data_i(0) & reg(7 downto 1); + reg_no_destuffing := data_i(0) & reg_no_destuffing(7 downto 1); + + if reg_no_destuffing(7 downto 1) = "0111110" then + reg(7 downto 0) := reg(6 downto 0) & '0'; + + elsif ongoing = '1' then + cnter := cnter + 1; + + end if; + + if reg_no_destuffing = g_DELIMITER then + cnter := 0; + ongoing := '1'; + new_word_o <= '1'; + + elsif reg_no_destuffing = x"FF" then + ongoing := '0'; + + end if; + + if cnter >= g_WORD_SIZE and ongoing = '1' then + cnter := 0; + data_o <= reg; + write_o <= '1'; + end if; + + end if; + end if; + + end process; + +end behaviour; +--============================================================================-- +--############################################################################-- +--============================================================================-- diff --git a/vldb/code/GBT-SC/IC/ic_rx.vhd b/vldb/code/GBT-SC/IC/ic_rx.vhd new file mode 100644 index 0000000..504a37d --- /dev/null +++ b/vldb/code/GBT-SC/IC/ic_rx.vhd @@ -0,0 +1,156 @@ +------------------------------------------------------- +--! @file +--! @author Julian Mendez (CERN - EP-ESE-BE) +--! @date April, 2017 +--! @version 1.0 +--! @brief IC control - Rx deserialization and decoding +------------------------------------------------------- + +--! Include the IEEE VHDL standard library +library ieee; +--! Use STD_Logic to define vector types +use ieee.std_logic_1164.all; +--! Used to convert std_logic_vector to integer and manage fifo pointer +use ieee.numeric_std.all; + +--! @brief IC_rx Entity - Rx deserialization and decoding +--! @details +--! The IC_rx entity handles the deserialization and decoding +--! of the received frame on the couple of bits dedicated to +--! the IC control. +entity ic_rx is + generic ( + g_FIFO_DEPTH: integer := 10 --! Depth of the internal FIFO used to improve the timming performance + ); + port ( + -- Clock and reset + rx_clk_i : in std_logic; --! Rx clock (Rx_frameclk_o from GBT-FPGA IP): must be a multiple of the LHC frequency + rx_clk_en : in std_logic; --! Rx clock enable signal must be used in case of multi-cycle path(rx_clk_i > LHC frequency). By default: always enabled + + reset_i : in std_logic; --! Reset all of the RX processes + + -- Status + rx_empty_o : out std_logic; --! Rx FIFO is empty (no reply from GBTx) + + -- Internal FIFO + rd_clk_i : in std_logic; + rd_i : in std_logic; --! Request a read operation of the internal FIFO (GBTx reply) + data_o : out std_logic_vector(7 downto 0); --! Data from the FIFO + + -- IC lines + rx_data_i : in std_logic_vector(1 downto 0) --! (RX) Array of bits from the GBT-Frame (bits 83/84) - IC line + ); +end ic_rx; + +--! @brief IC_rx Architecture - Rx deserialization and decoding +--! @details +--! The IC_rx architecture implements the two components used to manage the IC line +--! in order to decode the data received from the GBTx and store the information into +--! a FIFO. +architecture behaviour of ic_rx is + + -- Signals + signal byte_des : std_logic_vector(7 downto 0); --! Decoded word from deserializer + signal wr : std_logic; --! Write request to saved decoded word into the FIFO (from deserializer) + + -- Components + --! IC_deserializer component implements a state machine used to deserialize, decode and inform when a new command is received. + component ic_deserializer is + generic ( + g_WORD_SIZE : integer := 8; + g_DELIMITER : std_logic_vector(7 downto 0) := "01111110" + ); + port ( + clk_i : in std_logic; + rx_clk_en : in std_logic; + + reset_i : in std_logic; + + -- Data + data_i : in std_logic_vector(1 downto 0); + data_o : out std_logic_vector((g_WORD_SIZE-1) downto 0); + + -- Status + write_o : out std_logic; + new_word_o : out std_logic + ); + end component ic_deserializer; + + --! IC_rx_fifo contains the received data from the GBTx. + component ic_rx_fifo is + generic ( + g_FIFO_DEPTH : integer := 10; --! Depth of the internal FIFO used to improve the timming performance + g_WORD_SIZE : integer := 8 --! Size of the words to be stored + ); + port ( + wr_clk_i : in std_logic; --! Rx clock (Rx_frameclk_o from GBT-FPGA IP): must be a multiple of the LHC frequency + wr_clk_en_i : in std_logic; --! Rx clock enable signal must be used in case of multi-cycle path(rx_clk_i > LHC frequency). By default: always enabled + rd_clk_i : in std_logic; + reset_i : in std_logic; --! Reset all of the RX processes + + -- Data + data_i : in std_logic_vector((g_WORD_SIZE-1) downto 0); --! Input data (from deserializer) + data_o : out std_logic_vector((g_WORD_SIZE-1) downto 0); --! Data from the FIFO (read by the user) + + -- Control + write_i : in std_logic; --! Request a write into the FIFO (from deserializer) + read_i : in std_logic; --! Request a read (from user) + + --Status + rx_empty_o : out std_logic --! Ready to be read, FIFO is not empty + ); + end component ic_rx_fifo; + +begin --========#### Architecture Body ####========-- + + -- RX Deserializer + --! Instantiation of the deserializer component + Deserializer_inst: ic_deserializer + generic map( + g_WORD_SIZE => 8 + ) + port map( + clk_i => rx_clk_i, + rx_clk_en => rx_clk_en, + + reset_i => reset_i, + + -- Data + data_i => rx_data_i, + data_o => byte_des, + + -- Status + write_o => wr, + new_word_o => open + ); + + -- RX Fifo + --! Instantiation of the RX FIFO. + ic_rx_fifo_inst: ic_rx_fifo + generic map( + g_WORD_SIZE => 8, + g_FIFO_DEPTH => g_FIFO_DEPTH + ) + port map( + wr_clk_i => rx_clk_i, + wr_clk_en_i => rx_clk_en, + rd_clk_i => rd_clk_i, + + reset_i => reset_i, + + -- Data + data_i => byte_des, + data_o => data_o, + + -- Control + write_i => wr, + read_i => rd_i, + + -- Status + rx_empty_o => rx_empty_o + ); + +end behaviour; +--============================================================================-- +--############################################################################-- +--============================================================================-- \ No newline at end of file diff --git a/vldb/code/GBT-SC/IC/ic_rx_fifo.vhd b/vldb/code/GBT-SC/IC/ic_rx_fifo.vhd new file mode 100644 index 0000000..9b8fc89 --- /dev/null +++ b/vldb/code/GBT-SC/IC/ic_rx_fifo.vhd @@ -0,0 +1,114 @@ +------------------------------------------------------- +--! @file +--! @author Julian Mendez (CERN - EP-ESE-BE) +--! @date April, 2017 +--! @version 1.0 +--! @brief IC control - RX FIFO +------------------------------------------------------- + +--! Include the IEEE VHDL standard library +library ieee; +--! Use STD_Logic to define vector types +use ieee.std_logic_1164.all; +--! Used to convert std_logic_vector to integer and manage fifo pointer +use ieee.numeric_std.all; + +--! @brief IC_rx_fifo Entity - RX FIFO +--! @details +--! The IC_rx_fifo is used to store the reply from the GBTx +--! following a read/write command. It extracts the header +--! details (GBTx address, number of words, etc.) and provide +--! a generic fifo interface to get the data. +-- IEEE VHDL standard library: +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +--============================================================================-- +--############################ Entity ####################################-- +--============================================================================-- +entity ic_rx_fifo is + generic ( + g_FIFO_DEPTH : integer := 10; --! Depth of the internal FIFO used to improve the timming performance + g_WORD_SIZE : integer := 8 --! Size of the words to be stored + ); + port ( + wr_clk_i : in std_logic; --! Rx clock (Rx_frameclk_o from GBT-FPGA IP): must be a multiple of the LHC frequency + wr_clk_en_i : in std_logic; --! Rx clock enable signal must be used in case of multi-cycle path(rx_clk_i > LHC frequency). By default: always enabled + rd_clk_i : in std_logic; + reset_i : in std_logic; --! Reset all of the RX processes + + -- Data + data_i : in std_logic_vector((g_WORD_SIZE-1) downto 0); --! Input data (from deserializer) + data_o : out std_logic_vector((g_WORD_SIZE-1) downto 0); --! Data from the FIFO (read by the user) + + -- Control + write_i : in std_logic; --! Request a write into the FIFO (from deserializer) + read_i : in std_logic; --! Request a read (from user) + + --Status + rx_empty_o : out std_logic --! FIFO is empty + ); +end ic_rx_fifo; + + +--! @brief IC_rx_fifo Architecture - RX FIFO +--! @details +--! The IC_rx_fifo architecture implements the logic to store the received byte +--! and extract the header when a new_word_i flag is received. +architecture behavioral of ic_rx_fifo is + + -- Types + subtype reg_t is std_logic_vector((g_WORD_SIZE-1) downto 0); + type ramreg_t is array(integer range<>) of reg_t; + constant zero_ram_s : std_logic_vector((g_WORD_SIZE-1) downto 0) := (others => '0'); + + -- Signals + signal mem_arr : ramreg_t(g_FIFO_DEPTH downto 0); + + signal wr_ptr : integer range 0 to g_FIFO_DEPTH; + signal word_in_mem_size : integer range 0 to g_FIFO_DEPTH; + signal rd_ptr : integer range 0 to g_FIFO_DEPTH; + +begin --========#### Architecture Body ####========-- + + ram_proc_rd: process(reset_i, rd_clk_i) + begin + if reset_i = '1' then + rd_ptr <= 0; + rx_empty_o <= '1'; + + elsif rising_edge(rd_clk_i) then + if read_i = '1' and rd_ptr < word_in_mem_size then + rd_ptr <= rd_ptr + 1; + end if; + + if word_in_mem_size > rd_ptr then + rx_empty_o <= '0'; + else + rx_empty_o <= '1'; + end if; + + data_o <= mem_arr(rd_ptr); + end if; + end process; + + ram_proc_wr: process(reset_i, wr_clk_i) + begin + if reset_i = '1' then + wr_ptr <= 0; + word_in_mem_size <= 0; + mem_arr <= (others => zero_ram_s); + + elsif rising_edge(wr_clk_i) then + if write_i = '1' and wr_clk_en_i = '1' then + mem_arr(wr_ptr) <= data_i; + wr_ptr <= wr_ptr + 1; + word_in_mem_size <= word_in_mem_size + 1; + end if; + end if; + end process; +end architecture; +--============================================================================-- +--############################################################################-- +--============================================================================-- diff --git a/vldb/code/GBT-SC/IC/ic_top.vhd b/vldb/code/GBT-SC/IC/ic_top.vhd new file mode 100644 index 0000000..69d0239 --- /dev/null +++ b/vldb/code/GBT-SC/IC/ic_top.vhd @@ -0,0 +1,234 @@ +------------------------------------------------------- +--! @file +--! @author Julian Mendez (CERN - EP-ESE-BE) +--! @date April, 2017 +--! @version 1.0 +--! @brief IC control - TOP level +------------------------------------------------------- + +--! Include the IEEE VHDL standard library +library ieee; +--! Use STD_Logic to define vector types +use ieee.std_logic_1164.all; + +--! @brief IC_top Entity - TOP Level of the IC component +--! @details +--! The IC_top entity handles the communication with the GBTx internal control +--! module. It generates the 2 bits encoded with an HDLC subset encoding to +--! read and write the internal register of the ASIC. +entity ic_top is + generic ( + g_ToLpGBT : integer range 0 to 1 := 0; + g_FIFO_DEPTH : integer := 20; --! Depth of the internal FIFO used to improve the timming performance + g_LPGBT_VERS : std_logic := '1' --! Select lpGBT version ('0': 0, '1': 1) + ); + port ( + -- Clock and reset + tx_clk_i : in std_logic; --! Tx clock (Tx_frameclk_o from GBT-FPGA IP): must be a multiple of the LHC frequency + tx_clk_en : in std_logic; --! Tx clock enable signal must be used in case of multi-cycle path(tx_clk_i > LHC frequency). By default: always enabled + + rx_clk_i : in std_logic; --! Rx clock (Rx_frameclk_o from GBT-FPGA IP): must be a multiple of the LHC frequency + rx_clk_en : in std_logic; --! Rx clock enable signal must be used in case of multi-cycle path(rx_clk_i > LHC frequency). By default: always enabled + + rx_reset_i : in std_logic; --! Reset RX datapath + tx_reset_i : in std_logic; --! Reset TX datapath + + -- Configuration + tx_GBTx_address_i : in std_logic_vector(7 downto 0); --! I2C address of the GBTx + tx_register_addr_i : in std_logic_vector(15 downto 0); --! Address of the first register to be accessed + tx_nb_to_be_read_i : in std_logic_vector(15 downto 0); --! Number of words/bytes to be read (only for read transactions) + + parity_err_mask_i : in std_logic_vector(7 downto 0); + + -- Internal FIFO + wr_clk_i : in std_logic; --! Fifo's writing clock + tx_wr_i : in std_logic; --! Request a write operation into the internal FIFO (Data to GBTx) + tx_data_to_gbtx_i : in std_logic_vector(7 downto 0); --! Data to be written into the internal FIFO + + rd_clk_i : in std_logic; + rx_rd_i : in std_logic; --! Request a read operation of the internal FIFO (GBTx reply) + rx_data_from_gbtx_o : out std_logic_vector(7 downto 0); --! Data from the FIFO + + -- FSM Control + tx_start_write_i : in std_logic; --! Request a write config. to the GBTx + tx_start_read_i : in std_logic; --! Request a read config. to the GBTx + + -- Status + tx_ready_o : out std_logic; --! IC core ready for a transaction + rx_empty_o : out std_logic; --! Rx FIFO is empty (no reply from GBTx) + + -- IC lines + tx_data_o : out std_logic_vector(1 downto 0); --! (TX) Array of bits to be mapped to the TX GBT-Frame (bits 83/84) + rx_data_i : in std_logic_vector(1 downto 0) --! (RX) Array of bits to be mapped to the RX GBT-Frame (bits 83/84) + ); +end ic_top; + +--! @brief IC_top architecture - TOP Level of the IC component +--! @details +--! Writting and/or reading register to/from the GBTx is made in two steps. To improve the performance +--! and because the ASIC memory can be accessed by burst, an internal FIFO is implemented to store the +--! data to be sent or received. Then the access from the outside looks like a FIFO interface with +--! Read and write signals associated to their data busses. This file implements the TX and RX dedicated +--! component and only a few logic elements to invert the MSB/LSB order of the IC line (2 bits). +architecture behaviour of ic_top is + + -- Signals + --! Tx line is inverted (MSB/LSB) to get the same order as for the SCA communication line + signal data_ic_tx_inv : std_logic_vector(1 downto 0); + --! Tx line is inverted (MSB/LSB) to get the same order as for the SCA communication line + signal data_ic_rx_inv : std_logic_vector(1 downto 0); + + -- Components + --! @brief IC_tx Entity - Tx FIFO and encoding/serialization + --! @details + --! The IC_tx entity control the FIFO used to store the command to be sent + --! and perform the HDLC encoding in parallel of the serialization process. + component ic_tx + generic ( + g_FIFO_DEPTH : integer := 10; + g_LPGBT_VERS : std_logic := '1' + ); + port ( + -- Clock and reset + tx_clk_i : in std_logic; + tx_clk_en : in std_logic; + + reset_i : in std_logic; + + -- Status + tx_ready_o : out std_logic; + + -- Configuration + GBTx_address_i : in std_logic_vector(7 downto 0); + Register_addr_i : in std_logic_vector(15 downto 0); + nb_to_be_read_i : in std_logic_vector(15 downto 0); + + parity_err_mask_i : in std_logic_vector(7 downto 0); + + -- Internal FIFO + wr_clk_i : in std_logic; --! Fifo's writing clock + wr_i : in std_logic; + data_i : in std_logic_vector(7 downto 0); + + -- FSM Control + start_write : in std_logic; + start_read : in std_logic; + + -- IC line + tx_data_o : out std_logic_vector(1 downto 0) + ); + end component ic_tx; + + --! @brief IC_rx Entity - Rx deserialization and decoding + --! @details + --! The IC_rx entity handles the deserialization and decoding + --! of the received frame on the couple of bits dedicated to + --! the IC control. + component ic_rx is + generic ( + g_FIFO_DEPTH: integer := 10 + ); + port ( + -- Clock and reset + rx_clk_i : in std_logic; + rx_clk_en : in std_logic; + + reset_i : in std_logic; + + -- Status + rx_empty_o : out std_logic; + + -- Internal FIFO + rd_clk_i : in std_logic; + rd_i : in std_logic; + data_o : out std_logic_vector(7 downto 0); + + -- IC lines + rx_data_i : in std_logic_vector(1 downto 0) + ); + end component ic_rx; + + signal ic_rst_rx_s : std_logic; + +begin --========#### Architecture Body ####========-- + + gbtx_connectivity: if g_ToLpGBT = 0 generate + tx_data_o(0) <= data_ic_tx_inv(1); + tx_data_o(1) <= data_ic_tx_inv(0); + data_ic_rx_inv(0) <= rx_data_i(1); + data_ic_rx_inv(1) <= rx_data_i(0); + end generate; + + lpgbt_connectivity: if g_ToLpGBT = 1 generate + tx_data_o <= data_ic_tx_inv; + data_ic_rx_inv <= rx_data_i; + end generate; + + -- TX + tx_inst: ic_tx + generic map ( + g_FIFO_DEPTH => g_FIFO_DEPTH, + g_LPGBT_VERS => g_LPGBT_VERS + ) + port map ( + -- Clock and reset + tx_clk_i => tx_clk_i, + tx_clk_en => tx_clk_en, + + reset_i => tx_reset_i, + + -- Status + tx_ready_o => tx_ready_o, + + -- Configuration + GBTx_address_i => tx_GBTx_address_i, + Register_addr_i => tx_register_addr_i, + nb_to_be_read_i => tx_nb_to_be_read_i, + + parity_err_mask_i => parity_err_mask_i, + + + -- FSM Control + start_write => tx_start_write_i, + start_read => tx_start_read_i, + + -- Internal FIFO + wr_clk_i => wr_clk_i, + wr_i => tx_wr_i, + data_i => tx_data_to_gbtx_i, + + -- IC line + tx_data_o => data_ic_tx_inv + ); + + -- RX + + ic_rst_rx_s <= rx_reset_i or tx_start_write_i or tx_start_read_i; + + rx_inst: entity work.ic_rx + generic map ( + g_FIFO_DEPTH => g_FIFO_DEPTH + ) + port map ( + -- Clock and reset + rx_clk_i => rx_clk_i, + rx_clk_en => rx_clk_en, + + reset_i => ic_rst_rx_s, + + -- Status + rx_empty_o => rx_empty_o, + + -- Internal FIFO + rd_clk_i => rd_clk_i, + rd_i => rx_rd_i, + data_o => rx_data_from_gbtx_o, + + -- IC line + rx_data_i => data_ic_rx_inv + ); + +end behaviour; +--============================================================================-- +--############################################################################-- +--============================================================================-- \ No newline at end of file diff --git a/vldb/code/GBT-SC/IC/ic_tx.vhd b/vldb/code/GBT-SC/IC/ic_tx.vhd new file mode 100644 index 0000000..d90d40d --- /dev/null +++ b/vldb/code/GBT-SC/IC/ic_tx.vhd @@ -0,0 +1,1057 @@ +------------------------------------------------------- +--! @file +--! @author Julian Mendez (CERN - EP-ESE-BE) +--! @date April, 2017 +--! @version 1.0 +--! @brief IC control - Tx FIFO and encoding/serialization +------------------------------------------------------- + +--! Include the IEEE VHDL standard library +library ieee; +--! Use STD_Logic to define vector types +use ieee.std_logic_1164.all; +--! Used to convert std_logic_vector to integer and manage fifo pointer +use ieee.numeric_std.all; + +--! Include the work library +library work; + +--! @brief IC_tx Entity - Tx FIFO and encoding/serialization +--! @details +--! The IC_tx entity control the FIFO used to store the command to be sent +--! and perform the HDLC encoding in parallel of the serialization process. +entity ic_tx is + generic ( + g_FIFO_DEPTH : integer := 20; --! Depth of the internal FIFO used to improve the timming performance + g_LPGBT_VERS : std_logic := '1' --! Select lpGBT version ('0': 0, '1': 1) + ); + port ( + -- Clock and reset + tx_clk_i : in std_logic; --! Tx clock (Tx_frameclk_o from GBT-FPGA IP): must be a multiple of the LHC frequency + tx_clk_en : in std_logic; --! Tx clock enable signal must be used in case of multi-cycle path(tx_clk_i > LHC frequency). By default: always enabled + + reset_i : in std_logic; --! Reset all of the TX processes + + -- Status + tx_ready_o : out std_logic; --! IC core ready for a transaction + + -- Configuration + GBTx_address_i : in std_logic_vector(7 downto 0); --! I2C address of the GBTx + Register_addr_i : in std_logic_vector(15 downto 0); --! Address of the first register to be accessed + nb_to_be_read_i : in std_logic_vector(15 downto 0); --! Number of words/bytes to be read (only for read transactions) + + parity_err_mask_i : in std_logic_vector(7 downto 0); + + -- Internal FIFO + wr_clk_i : in std_logic; --! Fifo's writing clock + wr_i : in std_logic; --! Request a write operation into the internal FIFO (Data to GBTx) + data_i : in std_logic_vector(7 downto 0); --! Data to be written into the internal FIFO + + -- FSM Control + start_read : in std_logic; --! Request a write config. to the GBTx + start_write : in std_logic; --! Request a read config. to the GBTx + + -- IC lines + tx_data_o : out std_logic_vector(1 downto 0) --! (TX) Array of bits to be mapped to the TX GBT-Frame (bits 83/84) + ); +end ic_tx; + +--! @brief IC_tx architecture - Tx FIFO and encoding/serialization +--! @details +--! The IC_tx architecture describes the behavior of the two components used to manage the IC line +--! in order to send a specific command: write register/burst (consists of a specific header followed by the data) +--! or read register/burst (consists of a specific header to inform the start register and the number of +--! byte to be read). +architecture behaviour of ic_tx is + + -- Types & Subtypes + subtype reg2 is std_logic_vector(1 downto 0); --! Subtype: bus of 2 bits (IC and EC lines) + subtype reg8 is std_logic_vector(7 downto 0); --! Subtype: bus of 8 bits (Bytes) + subtype reg16 is std_logic_vector(15 downto 0); --! Subtype: bus of 16 bits (Used for the CRC computing) + subtype reg32 is std_logic_vector(31 downto 0); --! Subtype: bus of 32 bits (Used for the data) + + type reg8_arr is array(integer range <>) of reg8; --! Type: array of bytes + type reg16_arr is array(integer range <>) of reg16; --! Type: array of 16 bits buses + type reg2_arr is array(integer range <>) of reg2; --! Type: array of 2 bits buses + type reg32_arr is array(integer range <>) of reg32; --! Type: array of 32 bits buses + + -- Constant + constant DEL_PACKET : std_logic_vector(7 downto 0) := "01111110"; + + -- Types + --! The hdlcstate_t type defines the states available for the hdlcproc process + type hdlcstate_t is (s0_waitForStart, + s2_sendSOF, + s3_sendCommand, + s4_sendCRC, + s5_sendEOF); + + -- Signals + signal word_cnt : integer range 0 to g_FIFO_DEPTH; --! Counter used to count the number of data written into the FIFO (write command) + signal word_cnt_v : std_logic_vector(15 downto 0); --! Same as word_cnt but with a std_logic_vector type + signal wr_ptr : integer range 6 to (7+g_FIFO_DEPTH); --! Write pointer to manage the write position into the FIFO (reset value: 7, after the header) + + signal fifo : reg8_arr(g_FIFO_DEPTH+7 downto 0); --! FIFO memory: user defined depth + 7 bytes for the command header (GBTx documentation) + signal fifo_r : reg8_arr(g_FIFO_DEPTH+7 downto 0); --! FIFO memory: user defined depth + 7 bytes for the command header (GBTx documentation) + + signal cmd_len : integer range 0 to (7+g_FIFO_DEPTH); --! Save command length in register + signal tx_parity : std_logic_vector(7 downto 0); --! Tx Data parity (xor between data words) + signal parity : std_logic_vector(7 downto 0); --! Final parity register (xor between header words and tx_parity signal) + + + signal hdlc_state : hdlcstate_t := s0_waitForStart; --! HDLC encoding FSM state register + + + signal start_write_s0 : std_logic := '0'; --! Register to detect start_write pulse + signal start_read_s0 : std_logic := '0'; --! Register to detect start_read pulse + signal reset_fifo : std_logic := '0'; --! Reset synchronization signal between FIFO and HDLC FSM. FIFO is reseted when the command has been fully sent. + signal reset_fifo_r : std_logic := '0'; --! Reset synchronization signal between FIFO and HDLC FSM. FIFO is reseted when the command has been fully sent. + + signal ongoing_write_s : std_logic; + signal ongoing_read_s : std_logic; + signal ongoing_write_r : std_logic; + signal ongoing_read_r : std_logic; + signal ongoing_write_s0 : std_logic; + signal ongoing_read_s0 : std_logic; + + signal start_wr_s0 : std_logic; + signal start_rd_s0 : std_logic; +begin --========#### Architecture Body ####========-- + + word_cnt_v <= std_logic_vector(to_unsigned((word_cnt), 16)); + + gen_vers1 : if g_LPGBT_VERS = '1' generate + + -- TX Fifo + --! The wr_fifo process generate, create the command and store the data + --! to be sent. All of the signal are synchronous with the tx_clk_i + --! clock and can be managed at full speed (no use of the clk_en signal) + wr_fifo: process(wr_clk_i, reset_fifo_r) + begin + if reset_fifo_r = '1' then + ongoing_write_s <= '0'; + ongoing_read_s <= '0'; + word_cnt <= 0; + wr_ptr <= 6; + cmd_len <= 6; + + tx_parity <= (others => '0'); + + elsif rising_edge(wr_clk_i) then + + start_wr_s0 <= start_write; + start_rd_s0 <= start_read; + + if ongoing_write_s = '1' or ongoing_read_s = '1' then + null; -- Wait for end of transmission + + elsif start_wr_s0 = '0' and start_write = '1' then + fifo(0) <= GBTx_address_i(6 downto 0) & '0'; + fifo(1) <= "00000000"; + fifo(2) <= (word_cnt_v(7 downto 0)); + fifo(3) <= (word_cnt_v(15 downto 8)); + fifo(4) <= (Register_addr_i(7 downto 0)); + fifo(5) <= (Register_addr_i(15 downto 8)); + cmd_len <= wr_ptr; + + ongoing_write_s <= '1'; + + elsif start_rd_s0 = '0' and start_read = '1' then + fifo(0) <= GBTx_address_i(6 downto 0) & '1'; + fifo(1) <= "00000000"; + fifo(2) <= (nb_to_be_read_i(7 downto 0)); + fifo(3) <= (nb_to_be_read_i(15 downto 8)); + fifo(4) <= (Register_addr_i(7 downto 0)); + fifo(5) <= (Register_addr_i(15 downto 8)); + + cmd_len <= 6; + + ongoing_read_s <= '1'; + + elsif wr_i = '1' then + + fifo(wr_ptr) <= data_i; + tx_parity <= tx_parity xor data_i; + word_cnt <= word_cnt + 1; + wr_ptr <= wr_ptr + 1; + + end if; + + end if; + + end process; + + -- TX Serializer + --! The hdlcproc process encodes and serializes the command into the two + --! bits of the IC line. + --! The process implements the following state machine: + --! * *s0_waitForStart*: Wait for a start_write or start_read instruction and calculate the parity byte + --! * *s2_sendSOF*: Send start of frame delimiter (serialization of the "01111110" byte) + --! * *s3_sendCommand*: Read the FIFO and encode/serialize the data + --! * *s4_sendCRC*: Send the parity byte + --! * *s5_sendEOF*: Send end of frame delimiter (serialization of the "01111110" byte) + hdlcproc: process(tx_clk_i, reset_i) + + variable offset_pos : integer range 0 to 8; + variable reg_pos : integer range 0 to 8+g_FIFO_DEPTH; + variable high_lvl_cnter : integer range 0 to 6; + + begin + + if rising_edge(tx_clk_i) then + + if reset_i = '1' then + offset_pos := 0; + high_lvl_cnter := 0; + + reset_fifo <= '1'; + tx_ready_o <= '0'; + tx_data_o <= "11"; + + hdlc_state <= s0_waitForStart; + reg_pos := 0; + + elsif tx_clk_en = '1' then + + tx_ready_o <= '0'; + + ongoing_write_s0 <= ongoing_write_r; + ongoing_read_s0 <= ongoing_read_r; + + case hdlc_state is + + when s0_waitForStart => + + reset_fifo <= '0'; + + -- Send idle + reg_pos := 0; + tx_ready_o <= '1'; + + tx_data_o(1) <= '1'; + tx_data_o(0) <= '1'; + + -- Check start signal + if ongoing_write_s0 = '0' and ongoing_write_r = '1' then + + tx_ready_o <= '0'; + + -- Compute the parity word + parity <= + ( + tx_parity xor + GBTx_address_i(6 downto 0) & '0' xor + word_cnt_v(7 downto 0) xor + word_cnt_v(15 downto 8) xor + Register_addr_i(7 downto 0) xor + Register_addr_i(15 downto 8) + ) xor parity_err_mask_i; + + tx_data_o(1) <= DEL_PACKET(0); + tx_data_o(0) <= DEL_PACKET(1); + offset_pos := 2; + + hdlc_state <= s2_sendSOF; + + elsif ongoing_read_s0 = '0' and ongoing_read_r = '1' then + + tx_ready_o <= '0'; + + -- Compute the parity word + parity <= + ( + GBTx_address_i(6 downto 0) & '1' xor + nb_to_be_read_i(7 downto 0) xor + nb_to_be_read_i(15 downto 8) xor + Register_addr_i(7 downto 0) xor + Register_addr_i(15 downto 8) + ) xor parity_err_mask_i; + + tx_data_o(1) <= DEL_PACKET(0); + tx_data_o(0) <= DEL_PACKET(1); + offset_pos := 2; + + hdlc_state <= s2_sendSOF; + + end if; + + when s2_sendSOF => + -- Data have been copied into the vector buffer + -- -> The fifo can be reseted + + -- Send delimiter without bit stuffing + tx_data_o(1) <= DEL_PACKET(offset_pos); + tx_data_o(0) <= DEL_PACKET(offset_pos+1); + + offset_pos := offset_pos + 2; + + --make sure that the bit stuffing counter is always zeroed at the beginning of the transaction + high_lvl_cnter := 0; + + -- Delimiter has been fully sent? + if offset_pos > 7 then + offset_pos := 0; + hdlc_state <= s3_sendCommand; + end if; + + when s3_sendCommand => + + + -- Enough data to send 2 bits? + if offset_pos < 7 then + + -- (MSB) Bit stuffing? + if high_lvl_cnter >= 5 then + + tx_data_o(1) <= '0'; + high_lvl_cnter := 0; + + -- (MSB) Send data + else + + tx_data_o(1) <= fifo_r(reg_pos)(offset_pos); + if fifo_r(reg_pos)(offset_pos) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + offset_pos := offset_pos + 1; + + end if; + + -- (LSB) Bit stuffing? + if high_lvl_cnter >= 5 then + + tx_data_o(0) <= '0'; + high_lvl_cnter := 0; + + -- (LSB) Send data + else + + tx_data_o(0) <= fifo_r(reg_pos)(offset_pos); + if fifo_r(reg_pos)(offset_pos) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + offset_pos := offset_pos + 1; + + end if; + + -- End of command? + if offset_pos = 8 then + + offset_pos := 0; + + if reg_pos < (cmd_len-1) then + reg_pos := reg_pos + 1; + else + hdlc_state <= s4_sendCRC; + end if; + + end if; + + -- 1 bit still have to been sent, then CRC + elsif offset_pos < 8 then + + -- (MSB) Bit stuffing? + if high_lvl_cnter >= 5 then + + tx_data_o(1) <= '0'; + high_lvl_cnter := 0; + + tx_data_o(0) <= fifo_r(reg_pos)(7); + if fifo_r(reg_pos)(offset_pos) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + offset_pos := 0; + + if reg_pos < (cmd_len-1) then + reg_pos := reg_pos + 1; + else + hdlc_state <= s4_sendCRC; + end if; + + -- (MSB) Send data + else + + tx_data_o(1) <= fifo_r(reg_pos)(7); + if fifo_r(reg_pos)(offset_pos) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + -- (LSB) Bit stuffing? + if high_lvl_cnter >= 5 then + tx_data_o(0) <= '0'; + high_lvl_cnter := 0; + + offset_pos := 0; + + if reg_pos < (cmd_len-1) then + reg_pos := reg_pos + 1; + else + hdlc_state <= s4_sendCRC; + end if; + + elsif reg_pos < (cmd_len-1) then + + reg_pos := reg_pos + 1; + + tx_data_o(0) <= fifo_r(reg_pos)(0); + if fifo_r(reg_pos)(0) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + offset_pos := 1; + + else + tx_data_o(0) <= parity(0); + if parity(0) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + offset_pos := 1; + hdlc_state <= s4_sendCRC; + + end if; + + end if; + + end if; + + when s4_sendCRC => + + -- Enough data to send 2 bits? + if offset_pos < 7 then + + -- (MSB) Bit stuffing? + if high_lvl_cnter >= 5 then + + tx_data_o(1) <= '0'; + high_lvl_cnter := 0; + + -- (MSB) Send data + else + + tx_data_o(1) <= parity(offset_pos); + if parity(offset_pos) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + offset_pos := offset_pos + 1; + + end if; + + -- (LSB) Bit stuffing? + if high_lvl_cnter >= 5 then + + tx_data_o(0) <= '0'; + high_lvl_cnter := 0; + + -- (LSB) Send data + else + + tx_data_o(0) <= parity(offset_pos); + if parity(offset_pos) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + offset_pos := offset_pos + 1; + + end if; + + -- End of command? + if offset_pos = 8 then + + offset_pos := 0; + reset_fifo <= '1'; + hdlc_state <= s5_sendEOF; + + end if; + + -- 1 bit still have to been sent, then CRC + elsif offset_pos < 8 then + + -- (MSB) Bit stuffing? + if high_lvl_cnter >= 5 then + + tx_data_o(1) <= '0'; + high_lvl_cnter := 0; + + tx_data_o(0) <= parity(offset_pos); + + if parity(offset_pos) = '1' then + high_lvl_cnter := 1; + end if; + + offset_pos := 0; + reset_fifo <= '1'; + hdlc_state <= s5_sendEOF; + + -- (MSB) Send data + else + + tx_data_o(1) <= parity(offset_pos); + if parity(offset_pos) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + -- (LSB) Bit stuffing? + if high_lvl_cnter >= 5 then + tx_data_o(0) <= '0'; + + high_lvl_cnter := 0; + offset_pos := 0; + reset_fifo <= '1'; + hdlc_state <= s5_sendEOF; + + else + + tx_data_o(0) <= DEL_PACKET(0); + offset_pos := 1; + reset_fifo <= '1'; + hdlc_state <= s5_sendEOF; + + end if; + end if; + + end if; + + when s5_sendEOF => + + -- (MSB) Send delimiter + tx_data_o(1) <= DEL_PACKET(offset_pos); + offset_pos := offset_pos + 1; + + -- Fully sent? + if offset_pos > 7 then + + tx_data_o(0) <= '1'; + hdlc_state <= s0_waitForStart; + + else + + -- (LSB) Send delimiter + tx_data_o(0) <= DEL_PACKET(offset_pos); + offset_pos := offset_pos + 1; + + -- Fully sent? + if offset_pos > 7 then + hdlc_state <= s0_waitForStart; + end if; + + end if; + end case; + + end if; + + end if; + + end process; + + end generate gen_vers1; + + gen_vers0: if g_LPGBT_VERS = '0' generate + + -- TX Fifo + --! The wr_fifo process generate, create the command and store the data + --! to be sent. All of the signal are synchronous with the tx_clk_i + --! clock and can be managed at full speed (no use of the clk_en signal) + wr_fifo: process(wr_clk_i, reset_fifo_r) + begin + if reset_fifo_r = '1' then + ongoing_write_s <= '0'; + ongoing_read_s <= '0'; + word_cnt <= 0; + wr_ptr <= 7; + cmd_len <= 7; + tx_parity <= (others => '0'); + + elsif rising_edge(wr_clk_i) then + + start_wr_s0 <= start_write; + start_rd_s0 <= start_read; + + if ongoing_write_s = '1' or ongoing_read_s = '1' then + null; -- Wait for end of transmission + + elsif start_wr_s0 = '0' and start_write = '1' then + fifo(0) <= GBTx_address_i(6 downto 0) & '0'; + fifo(1) <= GBTx_address_i(6 downto 0) & '0'; + fifo(2) <= "00000000"; + fifo(3) <= (word_cnt_v(7 downto 0)); + fifo(4) <= (word_cnt_v(15 downto 8)); + fifo(5) <= (Register_addr_i(7 downto 0)); + fifo(6) <= (Register_addr_i(15 downto 8)); + cmd_len <= wr_ptr; + + ongoing_write_s <= '1'; + + elsif start_rd_s0 = '0' and start_read = '1' then + fifo(0) <= GBTx_address_i(6 downto 0) & '1'; + fifo(1) <= GBTx_address_i(6 downto 0) & '1'; + fifo(2) <= "00000000"; + fifo(3) <= (nb_to_be_read_i(7 downto 0)); + fifo(4) <= (nb_to_be_read_i(15 downto 8)); + fifo(5) <= (Register_addr_i(7 downto 0)); + fifo(6) <= (Register_addr_i(15 downto 8)); + + cmd_len <= 7; + + ongoing_read_s <= '1'; + + elsif wr_i = '1' then + + fifo(wr_ptr) <= data_i; + tx_parity <= tx_parity xor data_i; + word_cnt <= word_cnt + 1; + wr_ptr <= wr_ptr + 1; + + end if; + + end if; + + end process; + + -- TX Serializer + --! The hdlcproc process encodes and serializes the command into the two + --! bits of the IC line. + --! The process implements the following state machine: + --! * *s0_waitForStart*: Wait for a start_write or start_read instruction and calculate the parity byte + --! * *s2_sendSOF*: Send start of frame delimiter (serialization of the "01111110" byte) + --! * *s3_sendCommand*: Read the FIFO and encode/serialize the data + --! * *s4_sendCRC*: Send the parity byte + --! * *s5_sendEOF*: Send end of frame delimiter (serialization of the "01111110" byte) + hdlcproc: process(tx_clk_i, reset_i) + + variable offset_pos : integer range 0 to 8; + variable reg_pos : integer range 0 to 8+g_FIFO_DEPTH; + variable high_lvl_cnter : integer range 0 to 6; + + begin + + if rising_edge(tx_clk_i) then + + if reset_i = '1' then + offset_pos := 0; + high_lvl_cnter := 0; + + reset_fifo <= '1'; + tx_ready_o <= '0'; + tx_data_o <= "11"; + + hdlc_state <= s0_waitForStart; + reg_pos := 0; + + elsif tx_clk_en = '1' then + + tx_ready_o <= '0'; + + ongoing_write_s0 <= ongoing_write_r; + ongoing_read_s0 <= ongoing_read_r; + + case hdlc_state is + + when s0_waitForStart => + + reset_fifo <= '0'; + + -- Send idle + reg_pos := 0; + tx_ready_o <= '1'; + + tx_data_o(1) <= '1'; + tx_data_o(0) <= '1'; + + -- Check start signal + if ongoing_write_s0 = '0' and ongoing_write_r = '1' then + + tx_ready_o <= '0'; + + -- Compute the parity word + parity <= + ( + tx_parity xor + word_cnt_v(7 downto 0) xor + word_cnt_v(15 downto 8) xor + Register_addr_i(7 downto 0) xor + Register_addr_i(15 downto 8) + ) xor parity_err_mask_i; + + tx_data_o(1) <= DEL_PACKET(0); + tx_data_o(0) <= DEL_PACKET(1); + offset_pos := 2; + + hdlc_state <= s2_sendSOF; + + elsif ongoing_read_s0 = '0' and ongoing_read_r = '1' then + + tx_ready_o <= '0'; + + -- Compute the parity word + parity <= + ( + GBTx_address_i(6 downto 0) & '1' xor + nb_to_be_read_i(7 downto 0) xor + nb_to_be_read_i(15 downto 8) xor + Register_addr_i(7 downto 0) xor + Register_addr_i(15 downto 8) + ) xor parity_err_mask_i; + + tx_data_o(1) <= DEL_PACKET(0); + tx_data_o(0) <= DEL_PACKET(1); + offset_pos := 2; + + hdlc_state <= s2_sendSOF; + + end if; + + when s2_sendSOF => + -- Data have been copied into the vector buffer + -- -> The fifo can be reseted + + -- Send delimiter without bit stuffing + tx_data_o(1) <= DEL_PACKET(offset_pos); + tx_data_o(0) <= DEL_PACKET(offset_pos+1); + + offset_pos := offset_pos + 2; + + --make sure that the bit stuffing counter is always zeroed at the beginning of the transaction + high_lvl_cnter := 0; + + -- Delimiter has been fully sent? + if offset_pos > 7 then + offset_pos := 0; + hdlc_state <= s3_sendCommand; + end if; + + when s3_sendCommand => + + -- Enough data to send 2 bits? + if offset_pos < 7 then + + -- (MSB) Bit stuffing? + if high_lvl_cnter >= 5 then + + tx_data_o(1) <= '0'; + high_lvl_cnter := 0; + + -- (MSB) Send data + else + + tx_data_o(1) <= fifo_r(reg_pos)(offset_pos); + if fifo_r(reg_pos)(offset_pos) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + offset_pos := offset_pos + 1; + + end if; + + -- (LSB) Bit stuffing? + if high_lvl_cnter >= 5 then + + tx_data_o(0) <= '0'; + high_lvl_cnter := 0; + + -- (LSB) Send data + else + + tx_data_o(0) <= fifo_r(reg_pos)(offset_pos); + if fifo_r(reg_pos)(offset_pos) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + offset_pos := offset_pos + 1; + + end if; + + -- End of command? + if offset_pos = 8 then + + offset_pos := 0; + + if reg_pos < (cmd_len-1) then + reg_pos := reg_pos + 1; + else + hdlc_state <= s4_sendCRC; + end if; + + end if; + + -- 1 bit still have to been sent, then CRC + elsif offset_pos < 8 then + + -- (MSB) Bit stuffing? + if high_lvl_cnter >= 5 then + + tx_data_o(1) <= '0'; + high_lvl_cnter := 0; + + tx_data_o(0) <= fifo_r(reg_pos)(7); + if fifo_r(reg_pos)(offset_pos) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + offset_pos := 0; + + if reg_pos < (cmd_len-1) then + reg_pos := reg_pos + 1; + else + hdlc_state <= s4_sendCRC; + end if; + + -- (MSB) Send data + else + + tx_data_o(1) <= fifo_r(reg_pos)(7); + if fifo_r(reg_pos)(offset_pos) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + -- (LSB) Bit stuffing? + if high_lvl_cnter >= 5 then + tx_data_o(0) <= '0'; + high_lvl_cnter := 0; + + offset_pos := 0; + + if reg_pos < (cmd_len-1) then + reg_pos := reg_pos + 1; + else + hdlc_state <= s4_sendCRC; + end if; + + elsif reg_pos < (cmd_len-1) then + + reg_pos := reg_pos + 1; + + tx_data_o(0) <= fifo_r(reg_pos)(0); + if fifo_r(reg_pos)(0) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + offset_pos := 1; + + else + tx_data_o(0) <= parity(0); + if parity(0) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + offset_pos := 1; + hdlc_state <= s4_sendCRC; + + end if; + + end if; + + end if; + + when s4_sendCRC => + + -- Enough data to send 2 bits? + if offset_pos < 7 then + + -- (MSB) Bit stuffing? + if high_lvl_cnter >= 5 then + + tx_data_o(1) <= '0'; + high_lvl_cnter := 0; + + -- (MSB) Send data + else + + tx_data_o(1) <= parity(offset_pos); + if parity(offset_pos) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + offset_pos := offset_pos + 1; + + end if; + + -- (LSB) Bit stuffing? + if high_lvl_cnter >= 5 then + + tx_data_o(0) <= '0'; + high_lvl_cnter := 0; + + -- (LSB) Send data + else + + tx_data_o(0) <= parity(offset_pos); + if parity(offset_pos) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + offset_pos := offset_pos + 1; + + end if; + + -- End of command? + if offset_pos = 8 then + + offset_pos := 0; + reset_fifo <= '1'; + hdlc_state <= s5_sendEOF; + + end if; + + -- 1 bit still have to been sent, then CRC + elsif offset_pos < 8 then + + -- (MSB) Bit stuffing? + if high_lvl_cnter >= 5 then + + tx_data_o(1) <= '0'; + high_lvl_cnter := 0; + + tx_data_o(0) <= parity(offset_pos); + + if parity(offset_pos) = '1' then + high_lvl_cnter := 1; + end if; + + offset_pos := 0; + reset_fifo <= '1'; + hdlc_state <= s5_sendEOF; + + -- (MSB) Send data + else + + tx_data_o(1) <= parity(offset_pos); + if parity(offset_pos) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + -- (LSB) Bit stuffing? + if high_lvl_cnter >= 5 then + tx_data_o(0) <= '0'; + + high_lvl_cnter := 0; + offset_pos := 0; + reset_fifo <= '1'; + hdlc_state <= s5_sendEOF; + + else + + tx_data_o(0) <= DEL_PACKET(0); + offset_pos := 1; + reset_fifo <= '1'; + hdlc_state <= s5_sendEOF; + + end if; + end if; + + end if; + + when s5_sendEOF => + + -- (MSB) Send delimiter + tx_data_o(1) <= DEL_PACKET(offset_pos); + offset_pos := offset_pos + 1; + + -- Fully sent? + if offset_pos > 7 then + + tx_data_o(0) <= '1'; + hdlc_state <= s0_waitForStart; + + else + + -- (LSB) Send delimiter + tx_data_o(0) <= DEL_PACKET(offset_pos); + offset_pos := offset_pos + 1; + + -- Fully sent? + if offset_pos > 7 then + hdlc_state <= s0_waitForStart; + end if; + + end if; + end case; + + end if; + + end if; + + end process; + + end generate gen_vers0; + + -- Clock domain crossing + clockDomainCrossing_tofifo: process(wr_clk_i, reset_fifo) + begin + if reset_fifo = '1' then + reset_fifo_r <= '1'; + + elsif rising_edge(wr_clk_i) then + reset_fifo_r <= '0'; + end if; + end process; + + clockDomainCrossing_tohdlc_rd: process(tx_clk_i, ongoing_read_s) + begin + if ongoing_read_s = '0' then + ongoing_read_r <= '0'; + elsif rising_edge(tx_clk_i) then + ongoing_read_r <= '1'; + end if; + end process; + + clockDomainCrossing_tohdlc_wr: process(tx_clk_i, ongoing_write_s) + begin + if ongoing_write_s = '0' then + ongoing_write_r <= '0'; + elsif rising_edge(tx_clk_i) then + ongoing_write_r <= '1'; + end if; + end process; + + clockDomainCrossing_tohdlc_fifo: process(tx_clk_i) + begin + if rising_edge(tx_clk_i) then + fifo_r <= fifo; + end if; + end process; + +end behaviour; +--============================================================================-- +--############################################################################-- +--============================================================================-- diff --git a/vldb/code/GBT-SC/SCA/sca_deserializer.vhd b/vldb/code/GBT-SC/SCA/sca_deserializer.vhd new file mode 100644 index 0000000..0a86ec0 --- /dev/null +++ b/vldb/code/GBT-SC/SCA/sca_deserializer.vhd @@ -0,0 +1,148 @@ +------------------------------------------------------- +--! @file +--! @author Julian Mendez (CERN - EP-ESE-BE) +--! @date April, 2017 +--! @version 1.0 +--! @brief SCA control - EC Field deserializer +------------------------------------------------------- + +--! Include the IEEE VHDL standard library +library ieee; +--! Use STD_Logic to define vector types +use ieee.std_logic_1164.all; +--! Used to convert std_logic_vector to integer and manage fifo pointer +use ieee.numeric_std.all; + +--! @brief SCA_Deserializer Entity - EC Field deserializer +--! @details +--! The EC_Deserializer deserializes the data and removes the zeros +--! inserted as specified by the HDLC standard (bit stuffing). +--! Additionally, it detects the delimiter pattern to inform the +--! core when a new frame is received. +entity sca_deserializer is + generic ( + g_WORD_SIZE : integer := 8; --! Size of the words to be stored into the external FIFO + g_DELIMITER : std_logic_vector(7 downto 0) := "01111110"; --! Delimiter pattern + g_IDLE : std_logic_vector(7 downto 0) := "01111111" --! IDLE pattern + ); + port ( + rx_clk_i : in std_logic; --! Rx clock (Rx_frameclk_o from GBT-FPGA IP): must be a multiple of the LHC frequency + clk_en : in std_logic; --! Rx clock enable signal must be used in case of multi-cycle path(rx_clk_i > LHC frequency). By default: always enabled + + reset_i : in std_logic; --! Reset the deserializer + + -- Data + data_i : in std_logic_vector(1 downto 0); --! (RX) Couple of bits from the GBT-Frame - EC line + data_o : out std_logic_vector((g_WORD_SIZE-1) downto 0); --! Deserialized/decoded data + + -- Control & status + write_o : out std_logic; --! Write request to the external FIFO + delimiter_found_o : out std_logic --! Delimiter detected flag (new command received) + ); +end sca_deserializer; + +--! @brief SCA_Deserializer Architecture - SCA Field deserializer +--! @details +--! The SCA_Deserializer architecture describes the logic required to +--! deserialize the input and decode the "HDLC" frame. The decoding +--! consists in removing the '0' inserted every 5 consecutive high level bits +--! bits and detecting/removing the delimiter packets (SOF/EOF). +architecture behavioral of sca_deserializer is +begin --========#### Architecture Body ####========-- + + --! @brief Deserializer process: manages the decoding/deserialization + --! @details + --! The deserialization is based on a counter, used to control the write_o + --! signal (set to '1' when cnter value >= to the word size). The counter + --! is reseted when a delimiter is received (to synchronize the system) and + --! incremented when a valid bit is received (not a '0' to be removed). + --! Finally, because of the size of the serial frame (2 bits and not only one), + --! the logic of the process is duplicated once. + --! An on-going signal is used to know wether the delimiter packet received + --! is a start or end of frame. + deserializer: process(reset_i, rx_clk_i) + + variable reg : std_logic_vector(7 downto 0); + variable reg_no_destuffing : std_logic_vector(7 downto 0); + variable cnter : integer; + variable ongoing : std_logic; + + begin + + if rising_edge(rx_clk_i) then + + if reset_i = '1' then + cnter := 0; + reg := (others => '0'); + reg_no_destuffing := (others => '0'); + + elsif clk_en = '1' then + + write_o <= '0'; + delimiter_found_o <= '0'; + + -- Data(MSB) + reg(7 downto 0) := data_i(1) & reg(7 downto 1); + reg_no_destuffing := data_i(1) & reg_no_destuffing(7 downto 1); + + if reg_no_destuffing(7 downto 1) = "0111110" then + reg(7 downto 0) := reg(6 downto 0) & '0'; + + elsif ongoing = '1' then + cnter := cnter + 1; + + end if; + + if reg_no_destuffing = g_DELIMITER then + cnter := 0; + ongoing := '1'; + delimiter_found_o <= '1'; + + elsif reg_no_destuffing = x"FF" or reg_no_destuffing = g_IDLE then + ongoing := '0'; + + end if; + + if cnter >= 8 and ongoing = '1' then + cnter := 0; + data_o <= reg; + write_o <= '1'; + end if; + + -- Data(LSB) + reg(7 downto 0) := data_i(0) & reg(7 downto 1); + reg_no_destuffing := data_i(0) & reg_no_destuffing(7 downto 1); + + if reg_no_destuffing(7 downto 1) = "0111110" then + reg(7 downto 0) := reg(6 downto 0) & '0'; + + elsif ongoing = '1' then + cnter := cnter + 1; + + end if; + + if reg_no_destuffing = g_DELIMITER then + cnter := 0; + ongoing := '1'; + delimiter_found_o <= '1'; + + elsif reg_no_destuffing = x"FF" or reg_no_destuffing = g_IDLE then + ongoing := '0'; + + end if; + + if cnter >= 8 and ongoing = '1' then + cnter := 0; + data_o <= reg; + write_o <= '1'; + end if; + end if; + + end if; + + end process; + +end behavioral; +--============================================================================-- +--############################################################################-- +--============================================================================-- diff --git a/vldb/code/GBT-SC/SCA/sca_pkg.vhd b/vldb/code/GBT-SC/SCA/sca_pkg.vhd new file mode 100644 index 0000000..68f907a --- /dev/null +++ b/vldb/code/GBT-SC/SCA/sca_pkg.vhd @@ -0,0 +1,111 @@ +------------------------------------------------------- +--! @file +--! @author Julian Mendez (CERN - EP-ESE-BE) +--! @date April, 2017 +--! @version 1.0 +--! @brief SCA control - SCA Package (types and CRC func.) +------------------------------------------------------- + +--! Include the IEEE VHDL standard library +library ieee; +--! Use STD_Logic to define vector types +use ieee.std_logic_1164.all; + +--! @brief SCA control - SCA Package (types and CRC func.) +--! @details +--! The SCA package defines new types and array required to +--! handle the communication with the SCA. It defines also +--! a couple of function needed to compute the HDLC frame +--! CRC. +package SCA_PKG is + + -- Types & Subtypes + subtype reg2 is std_logic_vector(1 downto 0); --! Subtype: bus of 2 bits (IC and EC lines) + subtype reg8 is std_logic_vector(7 downto 0); --! Subtype: bus of 8 bits (Bytes) + subtype reg16 is std_logic_vector(15 downto 0); --! Subtype: bus of 16 bits (Used for the CRC computing) + subtype reg32 is std_logic_vector(31 downto 0); --! Subtype: bus of 32 bits (Used for the data) + + type reg8_arr is array(integer range <>) of reg8; --! Type: array of bytes + type reg16_arr is array(integer range <>) of reg16; --! Type: array of 16 bits buses + type reg2_arr is array(integer range <>) of reg2; --! Type: array of 2 bits buses + type reg32_arr is array(integer range <>) of reg32; --! Type: array of 32 bits buses + + -- Functions + --! Reverse function is used to reverse the CRC before sending it. The standard + --! requires to send the 16 bits from the LSB to the MSB. + function reverse_v ( + a: in std_logic_vector) + return std_logic_vector; + + --! nextCRC16_D8 function compute the 16 bits CRC, using the new byte to be sent + --! and the current CRC value. + function nextCRC16_D8 ( + Data: std_logic_vector(7 downto 0); + crc: std_logic_vector(15 downto 0)) + return std_logic_vector; + +end SCA_PKG; + +--! @brief SCA control - SCA Package body (describes func.) +--! @details +--! The SCA package body implements the reverse and nextCRC16_D8 +--! functions available via the SCA_PKG package. +package body SCA_PKG is + + -- Vector reverse function + --! Reverse function is used to reverse the CRC before sending it. The standard + --! requires to send the 16 bits from the LSB to the MSB. + function reverse_v ( + a: in std_logic_vector) + return std_logic_vector is + + variable result: std_logic_vector(a'RANGE); + alias aa: std_logic_vector(a'REVERSE_RANGE) is a; + + begin + for i in aa'RANGE loop + result(i) := aa(i); + end loop; + + return result; + end; + + -- CRC16 - 8bits data + --! nextCRC16_D8 function compute the 16 bits CRC, using the new byte to be sent + --! and the current CRC value. + function nextCRC16_D8 ( + Data: std_logic_vector(7 downto 0); + crc: std_logic_vector(15 downto 0)) + return std_logic_vector is + + variable d: std_logic_vector(7 downto 0); + variable c: std_logic_vector(15 downto 0); + variable newcrc: std_logic_vector(15 downto 0); + + begin + + d := Data; + c := crc; + + newcrc(0) := d(4) xor d(0) xor c(8) xor c(12); + newcrc(1) := d(5) xor d(1) xor c(9) xor c(13); + newcrc(2) := d(6) xor d(2) xor c(10) xor c(14); + newcrc(3) := d(7) xor d(3) xor c(11) xor c(15); + newcrc(4) := d(4) xor c(12); + newcrc(5) := d(5) xor d(4) xor d(0) xor c(8) xor c(12) xor c(13); + newcrc(6) := d(6) xor d(5) xor d(1) xor c(9) xor c(13) xor c(14); + newcrc(7) := d(7) xor d(6) xor d(2) xor c(10) xor c(14) xor c(15); + newcrc(8) := d(7) xor d(3) xor c(0) xor c(11) xor c(15); + newcrc(9) := d(4) xor c(1) xor c(12); + newcrc(10) := d(5) xor c(2) xor c(13); + newcrc(11) := d(6) xor c(3) xor c(14); + newcrc(12) := d(7) xor d(4) xor d(0) xor c(4) xor c(8) xor c(12) xor c(15); + newcrc(13) := d(5) xor d(1) xor c(5) xor c(9) xor c(13); + newcrc(14) := d(6) xor d(2) xor c(6) xor c(10) xor c(14); + newcrc(15) := d(7) xor d(3) xor c(7) xor c(11) xor c(15); + + return newcrc; + + end nextCRC16_D8; + +end SCA_PKG; \ No newline at end of file diff --git a/vldb/code/GBT-SC/SCA/sca_rx.vhd b/vldb/code/GBT-SC/SCA/sca_rx.vhd new file mode 100644 index 0000000..343a812 --- /dev/null +++ b/vldb/code/GBT-SC/SCA/sca_rx.vhd @@ -0,0 +1,203 @@ +------------------------------------------------------- +--! @file +--! @author Julian Mendez (CERN - EP-ESE-BE) +--! @date April, 2017 +--! @version 1.0 +--! @brief SCA control - SCA RX (HDLC decoder) +------------------------------------------------------- + +--! Include the IEEE VHDL standard library +library ieee; +--! Use STD_Logic to define vector types +use ieee.std_logic_1164.all; +--! Used to convert std_logic_vector to integer and manage fifo pointer +use ieee.numeric_std.all; + +--! @brief SCA_rx Entity - SCA RX (HDLC decoder) +--! @details +--! The SCA_rx entity handles the deserialization and decoding +--! of the received frame on the couple of bits dedicated to +--! the EC control. +entity sca_rx is + port ( + -- Clock & reset + rx_clk_i : in std_logic; --! Rx clock (Rx_frameclk_o from GBT-FPGA IP): must be a multiple of the LHC frequency + clk_en : in std_logic; --! Rx clock enable signal must be used in case of multi-cycle path(rx_clk_i > LHC frequency). By default: always enabled + + reset_i : in std_logic; --! Reset RX datapath + + -- Satus + done_o : out std_logic; --! Reply received flag (pulse) + crc_err_o : out std_logic; --! CRC Error detected on received frame (not supported yet) + + -- RX data + address_o : out std_logic_vector(7 downto 0); --! Reply: address field (According to the SCA manual) + control_o : out std_logic_vector(7 downto 0); --! Reply: control field (According to the SCA manual) + transID_o : out std_logic_vector(7 downto 0); --! Reply: transaction ID field (According to the SCA manual) + channel_o : out std_logic_vector(7 downto 0); --! Reply: channel field (According to the SCA manual) + len_o : out std_logic_vector(7 downto 0); --! Reply: len field (According to the SCA manual) + error_o : out std_logic_vector(7 downto 0); --! Reply: error field (According to the SCA manual) + data_o : out std_logic_vector(31 downto 0); --! Reply: data field (According to the SCA manual) + + -- IC Line + rx_data_i : in std_logic_vector(1 downto 0) --! (RX) EC line from the RX GBT-Frame + ); +end sca_rx; + +--! @brief SCA_rx Architecture - SCA RX (HDLC decoder) +--! @details +--! The SCA_rx architecture implements the components and logic used to manage the EC line +--! in order to decode the data received from the SCA and format the command received. The +--! deserializer synchronize and control a FIFO. The deserialized bytes are saved and +--! set in output of the FIFO when a delimiter packet is detected (EOF). Finally, a few +--! logic elements are implemented to format the reply and to connect the data to the reply buses. +architecture behaviour of sca_rx is + + -- Signals + signal byte_from_des_s : std_logic_vector(7 downto 0); --! Deserialized word (from deserializer) + signal wr_command_s : std_logic; --! Write command to the internal FIFO (from deserializer) + signal delimiter_detected_s : std_logic; --! Delimiter detected flag (from deserializer), used to generate reply received flag + + signal cmd_v : std_logic_vector(159 downto 0); --! parallelized command (from FIFO) + + signal data_word_s2 : std_logic_vector(31 downto 0); --! Data word from the command when len = 2 bytes + signal data_word_s4 : std_logic_vector(31 downto 0); --! Data word from the command when len = 4 bytes + signal len_s : std_logic_vector(7 downto 0); --! Computed length of the command (field value from the SCA is wrong) + + signal fifo_cnt : std_logic_vector(7 downto 0); --! Number of word in FIFO (std_logic_vector) + signal fifo_cnt_i : integer range 0 to 15; --! Number of word in FIFO (integer - used to compute the reply length) + signal len_from_fifo : integer range 0 to 15; --! Computed data length (number of word in FIFO - 8 bytes of header) + + signal rx_received_s : std_logic; --! Reply received flag (from FIFO) + + -- Components + --! @brief SCA_Deserializer Entity - EC line deserializer + --! @details + --! The SCA_Deserializer entity deserializes the EC line and control the FIFO + --! to save the 8bit words. + component sca_deserializer is + generic ( + g_WORD_SIZE : integer := 8; + g_DELIMITER : std_logic_vector(7 downto 0) := "01111110"; + g_IDLE : std_logic_vector(7 downto 0) := "01111111" + ); + port ( + rx_clk_i : in std_logic; + clk_en : in std_logic; + + reset_i : in std_logic; + + -- Data + data_i : in std_logic_vector(1 downto 0); + data_o : out std_logic_vector((g_WORD_SIZE-1) downto 0); + + -- Control & status + write_o : out std_logic; + delimiter_found_o : out std_logic + ); + end component sca_deserializer; + + --! @brief SCA_Rx_FIFO Entity - EC RX FIFO + --! @details + --! The SCA_Rx_FIFO entity is used to save the deserialized word before + --! formating the command when the frame has been fully received. + component sca_rx_fifo is + generic ( + g_DEPTH : integer := 20; + g_SIZE : integer := 8 + ); + port ( + rx_clk_i : in std_logic; + clk_en : in std_logic; + + reset_i : in std_logic; + + -- Data + data_i : in std_logic_vector((g_SIZE-1) downto 0); + data_o : out std_logic_vector(((g_SIZE*g_DEPTH)-1) downto 0); + + -- Control + new_word_i : in std_logic; + write_i : in std_logic; + + --Status + to_be_read_o : out std_logic; + len_o : out std_logic_vector(7 downto 0) + ); + end component sca_rx_fifo; + +begin --========#### Architecture Body ####========-- + + sca_deserializer_inst: sca_deserializer + port map( + rx_clk_i => rx_clk_i, + clk_en => clk_en, + + reset_i => reset_i, + + -- Data + data_i => rx_data_i, + data_o => byte_from_des_s, + + -- Control & status + write_o => wr_command_s, + delimiter_found_o => delimiter_detected_s + ); + + sca_rx_fifo_inst: sca_rx_fifo + port map( + rx_clk_i => rx_clk_i, + clk_en => clk_en, + reset_i => reset_i, + + -- Data + data_i => byte_from_des_s, + data_o => cmd_v, + + -- Control + write_i => wr_command_s, + new_word_i => delimiter_detected_s, + + -- Status + to_be_read_o => rx_received_s, + len_o => fifo_cnt + ); + + -- Filters SREJ replies + done_o <= rx_received_s; -- when cmd_v(8) /= '1' else + --'0'; + + -- Preparation + fifo_cnt_i <= to_integer(unsigned(fifo_cnt)); + + len_from_fifo <= fifo_cnt_i - 8 when cmd_v(8) /= '1' and fifo_cnt_i > 8 + else 0; + + len_s <= std_logic_vector(to_unsigned(len_from_fifo,8)); + --cmd_v(47 downto 40) when cmd_v(8) /= '1' else + -- x"00"; + + data_word_s2 <= cmd_v(63 downto 56) & -- Dx + cmd_v(55 downto 48) & -- Dx + x"0000"; -- LSB (x"0000") + + data_word_s4 <= cmd_v(63 downto 56) & -- Dx + cmd_v(55 downto 48) & -- Dx + cmd_v(79 downto 72) & -- Dx + cmd_v(71 downto 64); -- Dx + + -- Link the fields to the output + address_o <= cmd_v(7 downto 0); + control_o <= cmd_v(15 downto 8); + transID_o <= cmd_v(23 downto 16) when cmd_v(8) /= '1' else x"00"; + channel_o <= cmd_v(31 downto 24) when cmd_v(8) /= '1' else x"00"; + error_o <= cmd_v(39 downto 32) when cmd_v(8) /= '1' else x"00"; + len_o <= std_logic_vector(to_unsigned(len_from_fifo,8)); + data_o <= data_word_s2 when (len_s = x"01" or len_s = x"02") else + data_word_s4 when (len_s = x"03" or len_s = x"04") else + x"00000000"; + +end behaviour; +--============================================================================-- +--############################################################################-- +--============================================================================-- \ No newline at end of file diff --git a/vldb/code/GBT-SC/SCA/sca_rx_fifo.vhd b/vldb/code/GBT-SC/SCA/sca_rx_fifo.vhd new file mode 100644 index 0000000..20dc341 --- /dev/null +++ b/vldb/code/GBT-SC/SCA/sca_rx_fifo.vhd @@ -0,0 +1,108 @@ +------------------------------------------------------- +--! @file +--! @author Julian Mendez (CERN - EP-ESE-BE) +--! @date April, 2017 +--! @version 1.0 +--! @brief SCA Control - SCA RX FIFO +------------------------------------------------------- + +--! Include the IEEE VHDL standard library +library ieee; +--! Use STD_Logic to define vector types +use ieee.std_logic_1164.all; +--! Used to convert std_logic_vector to integer and manage fifo pointer +use ieee.numeric_std.all; + +--! @brief SCA_rx_fifo Entity - SCA RX FIFO +--! @details +--! The SCA_rx_fifo is used to store the deserialized bytes from +--! the EC line. Then, the bytes are concatenate to provide one +--! word command when a delimiter (EOF) is received. +entity sca_rx_fifo is + generic ( + g_DEPTH : integer := 20; --! Depth of the FIFO + g_SIZE : integer := 8 --! Size of the input vectors + ); + port ( + rx_clk_i : in std_logic; --! Rx clock (Rx_frameclk_o from GBT-FPGA IP): must be a multiple of the LHC frequency + clk_en : in std_logic; --! Rx clock enable signal must be used in case of multi-cycle path(rx_clk_i > LHC frequency). By default: always enabled + + reset_i : in std_logic; --! Reset the FIFO + + -- Data + data_i : in std_logic_vector((g_SIZE-1) downto 0); --! Input word (g_DEPTH length) + data_o : out std_logic_vector(((g_SIZE*g_DEPTH)-1) downto 0); --! Output word (g_DEPTH*g_SIZE length) + + -- Control + new_word_i : in std_logic; --! Equivalent to a read command. It reset the FIFO and concatanate all of the words of the memory to the data_o output register + write_i : in std_logic; --! Request a write into the FIFO + + --Status + to_be_read_o : out std_logic; --! Flag generated when new_word command is received and FIFO len > 0 + len_o : out std_logic_vector(7 downto 0) --! Number of bytes stored into the FIFO + ); +end sca_rx_fifo; + + +--! @brief SCA_rx_fifo Architecture - SCA RX FIFO +--! @details +--! The SCA_rx_fifo architecture implements the logic to save data with a specific +--! size and concatenate and the memory array to provide a unique word output when +--! a new_word_i flag is received. +architecture behaviour of sca_rx_fifo is + + -- Types + subtype reg is std_logic_vector((g_SIZE-1) downto 0); + type ramreg_t is array(integer range<>) of reg; + + -- Signals + signal mem_arr: ramreg_t(g_DEPTH-1 downto 0); + signal wr_ptr: integer range 0 to g_DEPTH-1; + +begin --========#### Architecture Body ####========-- + + ram_proc: process(reset_i, rx_clk_i) + begin + + if rising_edge(rx_clk_i) then + + if reset_i = '1' then + wr_ptr <= 0; + data_o <= (others => '0'); + + for i in 0 to g_DEPTH-1 loop + mem_arr(i) <= (others => '0'); + end loop; + + elsif clk_en = '1' then + + to_be_read_o <= '0'; + + if write_i = '1' then + mem_arr(wr_ptr) <= data_i; + wr_ptr <= wr_ptr + 1; + + elsif new_word_i = '1' and wr_ptr > 0 then + + to_be_read_o <= '1'; + len_o <= std_logic_vector(to_unsigned(wr_ptr,8)); + wr_ptr <= 0; + + for i in 0 to g_DEPTH-1 loop + mem_arr(i) <= (others => '0'); + end loop; + + for i in 1 to g_DEPTH loop + data_o(((8*i)-1) downto ((i-1)*8)) <= mem_arr(i-1); + end loop; + + end if; + end if; + end if; + + end process; + +end behaviour; +--============================================================================-- +--############################################################################-- +--============================================================================-- diff --git a/vldb/code/GBT-SC/SCA/sca_top.vhd b/vldb/code/GBT-SC/SCA/sca_top.vhd new file mode 100644 index 0000000..9bb3499 --- /dev/null +++ b/vldb/code/GBT-SC/SCA/sca_top.vhd @@ -0,0 +1,231 @@ +------------------------------------------------------- +--! @file +--! @author Julian Mendez (CERN - EP-ESE-BE) +--! @date April, 2017 +--! @version 1.0 +--! @brief SCA control - SCA top level +------------------------------------------------------- + +--! Include the IEEE VHDL standard library +library ieee; +--! Use STD_Logic to define vector types +use ieee.std_logic_1164.all; + +--! Include the work library +library work; +--! Use SCA Package to define specific types (vector arrays) +use work.SCA_PKG.all; + +--! @brief SCA_top Entity - SCA top level +--! @details +--! The SCA_top entity handles the communication with the SCA modules. +--! It generates the couple of bits encoded with the HDLC standard to +--! access the internal register of the ASIC. +entity sca_top is + generic ( + g_SCA_COUNT : integer := 1 --! Number of SCAs to be controlled through the link (up to 41) + ); + port ( + tx_clk_i : in std_logic; --! Tx clock (Tx_frameclk_o from GBT-FPGA IP): must be a multiple of the LHC frequency + tx_clk_en : in std_logic := '1'; --! Tx clock enable signal must be used in case of multi-cycle path(tx_clk_i > LHC frequency). By default: always enabled + + rx_clk_i : in std_logic; --! Rx clock (Rx_frameclk_o from GBT-FPGA IP): must be a multiple of the LHC frequency + rx_clk_en : in std_logic := '1'; --! Rx clock enable signal must be used in case of multi-cycle path(rx_clk_i > LHC frequency). By default: always enabled + + rx_reset_i : in std_logic; --! Reset RX datapath + tx_reset_i : in std_logic; --! Reset TX datapath + + enable_i : in std_logic_vector((g_SCA_COUNT-1) downto 0); --! Enable flag, bit position correspond to the SCA ID ('1': enabled / '0': Disabled) + start_reset_cmd_i : in std_logic; --! Send a reset command to the enabled SCAs + start_connect_cmd_i : in std_logic; --! Send a connect command to the enabled SCAs + start_command_i : in std_logic; --! Send the command set in input to the enabled SCAs + inject_crc_error : in std_logic; --! Emulate a CRC error + + tx_address_i : in std_logic_vector(7 downto 0); --! Command: address field (According to the SCA manual) + tx_transID_i : in std_logic_vector(7 downto 0); --! Command: transaction ID field (According to the SCA manual) + tx_channel_i : in std_logic_vector(7 downto 0); --! Command: channel field (According to the SCA manual) + tx_len_i : in std_logic_vector(7 downto 0); --! Command: Len field (not used anymore, fixed to 4 bytes) + tx_command_i : in std_logic_vector(7 downto 0); --! Command: command field (According to the SCA manual) + tx_data_i : in std_logic_vector(31 downto 0); --! Command: data field (According to the SCA manual) + + rx_received_o : out std_logic_vector((g_SCA_COUNT-1) downto 0); --! Reply received flag (pulse), bit position correspond to the SCA ID + rx_address_o : out reg8_arr((g_SCA_COUNT-1) downto 0); --! Reply: address field (According to the SCA manual) + rx_control_o : out reg8_arr((g_SCA_COUNT-1) downto 0); --! Reply: control field (According to the SCA manual) + rx_transID_o : out reg8_arr((g_SCA_COUNT-1) downto 0); --! Reply: transaction ID field (According to the SCA manual) + rx_channel_o : out reg8_arr((g_SCA_COUNT-1) downto 0); --! Reply: channel field (According to the SCA manual) + rx_len_o : out reg8_arr((g_SCA_COUNT-1) downto 0); --! Reply: len field (According to the SCA manual) + rx_error_o : out reg8_arr((g_SCA_COUNT-1) downto 0); --! Reply: error field (According to the SCA manual) + rx_data_o : out reg32_arr((g_SCA_COUNT-1) downto 0); --! Reply: data field (According to the SCA manual) + + tx_data_o : out reg2_arr((g_SCA_COUNT-1) downto 0); --! (TX) Array of 2 bits to be mapped to the TX GBT-Frame + rx_data_i : in reg2_arr((g_SCA_COUNT-1) downto 0) --! (RX) Array of 2 bits to be mapped to the RX GBT-Frame + + ); +end sca_top; + + +--! @brief SCA control Architecture - SCA top level +--! @details +--! The SCA top level architecture implements the TX and RX modules required +--! to handle the communication with the ASIC. Because multiple chips can +--! be controlled through one GBT link (using e-links), the instantiation is +--! duplicated. As many SCA_tx and SCA_rx components as SCAs ASICs to be +--! controlled are instantiated. The SCA_gen instance multiplies the module +--! number using a generate for loop. +architecture behaviour of sca_top is + + -- Signals + signal tx_control_s : reg8_arr((g_SCA_COUNT-1) downto 0); --! Control field of the HDLC frame is used to acknowledge the command received. Then this field is managed internally, using the received value + signal rx_control_s : reg8_arr((g_SCA_COUNT-1) downto 0); --! Received control field value + + signal start_command_s : std_logic_vector((g_SCA_COUNT-1) downto 0); --! Used to detect a start_command request with enable = '1' for a specific SCA link + signal start_connect_s : std_logic_vector((g_SCA_COUNT-1) downto 0); --! Used to detect a start_connect request with enable = '1' for a specific SCA link + signal start_reset_s : std_logic_vector((g_SCA_COUNT-1) downto 0); --! Used to detect a start_reset request with enable = '1' for a specific SCA link + + -- Components + --! @brief SCA_rx Entity - RX deserializer/decoder + --! @details + --! The SCA_rx entity handles the deserialization and decoding + --! of the received frame on the couple of bits dedicated to + --! the SCA control. + component sca_rx is + port ( + -- Clock & reset + rx_clk_i : in std_logic; + clk_en : in std_logic; + + reset_i : in std_logic; + + -- Satus + done_o : out std_logic; + crc_err_o : out std_logic; -- Not supported yet + + -- RX data + address_o : out std_logic_vector(7 downto 0); + control_o : out std_logic_vector(7 downto 0); + transID_o : out std_logic_vector(7 downto 0); + channel_o : out std_logic_vector(7 downto 0); + len_o : out std_logic_vector(7 downto 0); + error_o : out std_logic_vector(7 downto 0); + data_o : out std_logic_vector(31 downto 0); + + -- IC Line + rx_data_i : in std_logic_vector(1 downto 0) + ); + end component sca_rx; + + --! @brief SCA_tx Entity - Tx encoding/serialization + --! @details + --! The IC_tx entity performs the HDLC encoding in parallel + --! of the serialization process. + component sca_tx is + port ( + clock : in std_logic; + clk_en : in std_logic; + + reset : in std_logic; + + start_input : in std_logic; + start_connect : in std_logic; + start_reset : in std_logic; + + address : in std_logic_vector(7 downto 0); + control : in std_logic_vector(7 downto 0); + transID : in std_logic_vector(7 downto 0); + channel : in std_logic_vector(7 downto 0); + len : in std_logic_vector(7 downto 0); + command : in std_logic_vector(7 downto 0); + data : in std_logic_vector(31 downto 0); + data_out : out std_logic_vector(1 downto 0); + + --Debug + crc_inj_err : in std_logic + + ); + end component sca_tx; + +begin --========#### Architecture Body ####========-- + + sca_gen: for i in 0 to (g_SCA_COUNT-1) generate + + start_command_s(i) <= enable_i(i) and start_command_i; + start_connect_s(i) <= enable_i(i) and start_connect_cmd_i; + start_reset_s(i) <= enable_i(i) and start_reset_cmd_i; + + --! @brief Time domain crossing (control field) + --! @details + --! Clock domain crossing for the control field is managed inside + --! of the ctrl_timedomain_crossing process. It just consist in + --! clocking the rx_control_s signal with the tx_clock. + --! Because no command must be sent before receiving the reply of + --! the previous one, we do not have any timing issue with the control + --! register. + ctrl_timedomain_crossing: process(tx_reset_i, tx_clk_i) + begin + + if rising_edge(tx_clk_i) then + + if tx_reset_i = '1' then + tx_control_s(i) <= x"00"; + else + tx_control_s(i) <= rx_control_s(i); + end if; + + end if; + + end process; + + -- TX: The command is sent to all of the SCA enabled + tx_inst: sca_tx + port map ( + clock => tx_clk_i, + clk_en => tx_clk_en, + + reset => tx_reset_i, + + start_input => start_command_s(i), + start_connect => start_connect_s(i), + start_reset => start_reset_s(i), + + address => tx_address_i, + control => tx_control_s(i), + transID => tx_transID_i, + channel => tx_channel_i, + len => tx_len_i, + command => tx_command_i, + data => tx_data_i, + + data_out => tx_data_o(i), + + crc_inj_err => inject_crc_error -- Used for test only + ); + + -- RX: individual for each SCA + rx_inst: sca_rx + port map( + rx_clk_i => rx_clk_i, + clk_en => rx_clk_en, + + reset_i => rx_reset_i, + + done_o => rx_received_o(i), + + address_o => rx_address_o(i), + control_o => rx_control_s(i), + transID_o => rx_transID_o(i), + channel_o => rx_channel_o(i), + len_o => rx_len_o(i), + error_o => rx_error_o(i), + data_o => rx_data_o(i), + + rx_data_i => rx_data_i(i) + ); + + rx_control_o(i) <= rx_control_s(i); + + end generate; + +end behaviour; +--============================================================================-- +--############################################################################-- +--============================================================================--' \ No newline at end of file diff --git a/vldb/code/GBT-SC/SCA/sca_tx.vhd b/vldb/code/GBT-SC/SCA/sca_tx.vhd new file mode 100644 index 0000000..b9dafc2 --- /dev/null +++ b/vldb/code/GBT-SC/SCA/sca_tx.vhd @@ -0,0 +1,537 @@ +------------------------------------------------------- +--! @file +--! @author Julian Mendez (CERN - EP-ESE-BE) +--! @date April, 2017 +--! @version 1.0 +--! @brief SCA control - SCA TX (HDLC encoder) +------------------------------------------------------- + +--! Include the IEEE VHDL standard library +library ieee; +--! Use STD_Logic to define vector types +use ieee.std_logic_1164.all; +--! Used to convert std_logic_vector to integer and use math functions (adder) +use ieee.numeric_std.all; + +--! Include the work library +library work; +--! Use SCA Package to define specific types (vector arrays) +use work.SCA_PKG.all; + +--! @brief SCA_tx Entity - Tx encoding/serialization +--! @details +--! The IC_tx entity performs the HDLC encoding in parallel +--! of the serialization process. +entity sca_tx is + port ( + clock : in std_logic; --! Tx clock (Tx_frameclk_o from GBT-FPGA IP): must be a multiple of the LHC frequency + clk_en : in std_logic; --! Tx clock enable signal must be used in case of multi-cycle path(tx_clk_i > LHC frequency). By default: always enabled + + reset : in std_logic; --! Reset TX datapath + + start_input : in std_logic; --! Send the command set in input + start_connect : in std_logic; --! Send a connect command + start_reset : in std_logic; --! Send a reset command + + address : in std_logic_vector(7 downto 0); --! Command: address field (According to the SCA manual) + control : in std_logic_vector(7 downto 0); --! Command: control field (According to the SCA manual) + transID : in std_logic_vector(7 downto 0); --! Command: transaction ID field (According to the SCA manual) + channel : in std_logic_vector(7 downto 0); --! Command: channel field (According to the SCA manual) + len : in std_logic_vector(7 downto 0); --! Command: Len field (not used anymore, fixed to 4 bytes) + command : in std_logic_vector(7 downto 0); --! Command: command field (According to the SCA manual) + data : in std_logic_vector(31 downto 0); --! Command: data field (According to the SCA manual) + data_out : out std_logic_vector(1 downto 0); --! (TX) Couple of bits to be connected to the SCA link + + --Debug + crc_inj_err : in std_logic --! Emulate a CRC error + + ); +end sca_tx; + +--! @brief SCA_tx Architecture - Tx encoding/serialization +--! @details +--! The SCA_tx architecture describes the logic used to generate the encoded frame +--! defined by the SCA manual. It is based on a state machine running at the tx_clock +--! frequency. Everytime the process is executed, two bits are generated and mapped +--! to the EC line. +architecture behaviour of sca_tx is + + -- Constants + constant IDLE_PACKET : std_logic_vector(7 downto 0) := "01111111"; --! Idle pattern as defined by the HDLC standard + constant DELIMITER_PACKET : std_logic_vector(7 downto 0) := "01111110"; --! Delimiter packet as defined by the HDLC standard (SOF/EOF) + + -- Type + --! The hdlcstate_t type defines the states available for the hdlcproc process + type hdlc_state_t is ( s0_waitForStart, + s1_waitForIdleFinished, + s2_sendSOF, + s3_sendCommand, + s4_sendCRC, + s5_sendEOF + ); + + -- Signals + signal hdlc_state : hdlc_state_t := s0_waitForStart; --! HDLC encoding FSM state register + + signal cmd_reg : reg8_arr(9 downto 0); --! Set of 8bit register that contains the command to be sent + signal cmd_len : integer range 0 to 10; --! Register to save the length of the command + + signal crc : std_logic_vector(15 downto 0); --! Register used to generate the CRC + signal rev_crc : std_logic_vector(15 downto 0); --! Inverted CRC + + signal ctrl_cnt : unsigned(2 downto 0); --! Internal control counter used to number the packet (must be incremented everytime a new command is sent) + +begin --========#### Architecture Body ####========-- + + rev_crc <= reverse_v(crc); + + -- HDLC process + --! The hdlcproc process encodes and serializes the command into the two + --! bits of the EC line. + --! The process implements the following state machine: + --! * *s0_waitForStart*: Serializes the IDLE_PACKET word until a start command. Upon a start, the cmd_reg set of register is filled out and the encoding start. + --! * *s1_waitForIdleFinished*: Sends the end of the IDLE_PACKET word. + --! * *s2_sendSOF*: Sends the SOF DELIMITER_PACKET word. + --! * *s3_sendCommand*: Sends the command registered into the cmd_reg with '0' insertion and CRC computing. + --! * *s4_sendCRC*: Sends the CRC computed during the previous stage (incl. '0' insertion). + --! * *s5_sendEOF*: Sends the EOF DELIMITER_PACKET word. + hdlcproc: process(clock, reset) + + variable offset_pos : integer range 0 to 17 := 0; + variable reg_pos : integer range 0 to 11 := 0; + variable high_lvl_cnter : integer range 0 to 6 := 0; + + begin + + if rising_edge(clock) then + + if reset = '1' then + data_out <= "11"; + offset_pos := 0; + reg_pos := 0; + ctrl_cnt <= (others => '0'); + cmd_len <= 0; + + elsif clk_en = '1' then + + case hdlc_state is + + when s0_waitForStart => + -- Generate tx_data_o + if offset_pos <= 6 then + data_out(1) <= IDLE_PACKET(offset_pos); + data_out(0) <= IDLE_PACKET(offset_pos+1); + + offset_pos := offset_pos + 2; + + if offset_pos > 7 then + offset_pos := 0; + end if; + + elsif offset_pos > 6 then + data_out(1) <= IDLE_PACKET(7); + data_out(0) <= IDLE_PACKET(0); + + offset_pos := 1; + end if; + + -- First word is always the address + cmd_reg(0) <= (address); + + -- Send command asked + if start_input = '1' then + + -- Control field computing + if crc_inj_err = '0' then + ctrl_cnt <= ctrl_cnt + 1; + end if; + + cmd_reg(1)(7) <= control(3) and not(control(0)); + cmd_reg(1)(6) <= control(2) and not(control(0)); + cmd_reg(1)(5) <= control(1) and not(control(0)); + cmd_reg(1)(4) <= '0'; + cmd_reg(1)(3 downto 1) <= std_logic_vector(ctrl_cnt); + cmd_reg(1)(0) <= '0'; + + -- Save in register + cmd_reg(2) <= (transID); + cmd_reg(3) <= (channel); + cmd_reg(4) <= (len); + cmd_reg(5) <= (command); + + -- JM: Not supported anymore because of SCA's issues + + --if len = x"01" or len = x"02" then + -- cmd_reg(6) <= (data(23 downto 16)); + -- cmd_reg(7) <= (data(31 downto 24)); + -- cmd_reg(8) <= x"00"; + -- cmd_reg(9) <= x"00"; + -- + -- cmd_len <= 8; + + --elsif len = x"03" or len = x"04" then + cmd_reg(6) <= (data(23 downto 16)); + cmd_reg(7) <= (data(31 downto 24)); + cmd_reg(8) <= (data(7 downto 0)); + cmd_reg(9) <= (data(15 downto 8)); + + cmd_len <= 10; + + --else + -- cmd_reg(6) <= (others => '0'); + -- cmd_reg(7) <= (others => '0'); + -- cmd_reg(8) <= (others => '0'); + -- cmd_reg(9) <= (others => '0'); + -- + -- cmd_len <= 10; + -- + --end if; + + offset_pos := 0; + hdlc_state <= s1_waitForIdleFinished; + + -- Send connect asked + elsif start_connect = '1' then + cmd_reg(1) <= x"2F"; + cmd_reg(2) <= (others => '0'); + cmd_len <= 2; + + offset_pos := 0; + hdlc_state <= s1_waitForIdleFinished; + + -- Send reset asked + elsif start_reset = '1' then + cmd_reg(1) <= x"8F"; + cmd_reg(2) <= (others => '0'); + cmd_len <= 2; + + offset_pos := 0; + hdlc_state <= s1_waitForIdleFinished; + + end if; + + when s1_waitForIdleFinished => + -- Send 8 times '1' + data_out <= "11"; + offset_pos := offset_pos + 2; + + if offset_pos > 7 then + hdlc_state <= s2_sendSOF; + offset_pos := 0; + end if; + + when s2_sendSOF => + + -- Send 8 times '1' + data_out(1) <= DELIMITER_PACKET(offset_pos); + data_out(0) <= DELIMITER_PACKET(offset_pos+1); + offset_pos := offset_pos + 2; + + if offset_pos > 7 then + hdlc_state <= s3_sendCommand; + reg_pos := 0; + offset_pos := 0; + + if crc_inj_err = '1' then + crc <= x"0000"; + + else + crc <= nextCRC16_D8( + reverse_v(cmd_reg(0)), + x"FFFF" + ); + end if; + + end if; + + high_lvl_cnter := 0; + + when s3_sendCommand => + + -- Enough data to send 2 bits? + if offset_pos < 7 then + + -- (MSB) Bit stuffing? + if high_lvl_cnter >= 5 then + + data_out(1) <= '0'; + high_lvl_cnter := 0; + + -- (MSB) Send data + else + + data_out(1) <= cmd_reg(reg_pos)(offset_pos); + if cmd_reg(reg_pos)(offset_pos) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + offset_pos := offset_pos + 1; + + end if; + + -- (LSB) Bit stuffing? + if high_lvl_cnter >= 5 then + + data_out(0) <= '0'; + high_lvl_cnter := 0; + + -- (LSB) Send data + else + + data_out(0) <= cmd_reg(reg_pos)(offset_pos); + if cmd_reg(reg_pos)(offset_pos) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + offset_pos := offset_pos + 1; + + end if; + + -- End of command? + if offset_pos = 8 then + + offset_pos := 0; + + if reg_pos < (cmd_len-1) then + reg_pos := reg_pos + 1; + crc <= nextCRC16_D8( + reverse_v( + cmd_reg(reg_pos) + ), + crc + ); + else + hdlc_state <= s4_sendCRC; + end if; + + end if; + + -- 1 bit still have to been sent, then CRC + elsif offset_pos < 8 then + + -- (MSB) Bit stuffing? + if high_lvl_cnter >= 5 then + + high_lvl_cnter := 0; + + data_out(1) <= '0'; + data_out(0) <= cmd_reg(reg_pos)(7); + + if cmd_reg(reg_pos)(offset_pos) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + offset_pos := 0; + + if reg_pos < (cmd_len-1) then + reg_pos := reg_pos + 1; + crc <= nextCRC16_D8( + reverse_v( + cmd_reg(reg_pos) + ), + crc + ); + else + hdlc_state <= s4_sendCRC; + end if; + + -- (MSB) Send data + else + + data_out(1) <= cmd_reg(reg_pos)(7); + if cmd_reg(reg_pos)(offset_pos) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + + -- (LSB) Bit stuffing? + if reg_pos < (cmd_len-1) then + + reg_pos := reg_pos + 1; + crc <= nextCRC16_D8( + reverse_v( + cmd_reg(reg_pos) + ), + crc + ); + + if high_lvl_cnter >= 5 then + data_out(0) <= '0'; + high_lvl_cnter := 0; + offset_pos := 0; + + else + data_out(0) <= cmd_reg(reg_pos)(0); + if cmd_reg(reg_pos)(0) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + offset_pos := 1; + end if; + + else + if high_lvl_cnter >= 5 then + data_out(0) <= '0'; + high_lvl_cnter := 0; + offset_pos := 0; + + else + data_out(0) <= rev_crc(0); + if rev_crc(0) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + offset_pos := 1; + + end if; + + hdlc_state <= s4_sendCRC; + + end if; + + end if; + + end if; + + when s4_sendCRC => + + -- Enough data to send 2 bits? + if offset_pos < 15 then + + -- (MSB) Bit stuffing? + if high_lvl_cnter >= 5 then + + data_out(1) <= '0'; + high_lvl_cnter := 0; + + -- (MSB) Send data + else + + data_out(1) <= rev_crc(offset_pos); + if rev_crc(offset_pos) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + offset_pos := offset_pos + 1; + + end if; + + -- (LSB) Bit stuffing? + if high_lvl_cnter >= 5 then + + data_out(0) <= '0'; + high_lvl_cnter := 0; + + -- (LSB) Send data + else + + data_out(0) <= rev_crc(offset_pos); + if rev_crc(offset_pos) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + offset_pos := offset_pos + 1; + + end if; + + -- End of command? + if offset_pos = 16 then + + offset_pos := 0; + hdlc_state <= s5_sendEOF; + + end if; + + -- 1 bit still have to been sent, then CRC + elsif offset_pos < 16 then + + -- (MSB) Bit stuffing? + if high_lvl_cnter >= 5 then + + high_lvl_cnter := 0; + + data_out(1) <= '0'; + data_out(0) <= rev_crc(offset_pos); + + if rev_crc(offset_pos) = '1' then + high_lvl_cnter := 0; + end if; + + offset_pos := 0; + hdlc_state <= s5_sendEOF; + + -- (MSB) Send data + else + + data_out(1) <= rev_crc(offset_pos); + if rev_crc(offset_pos) = '1' then + high_lvl_cnter := high_lvl_cnter + 1; + else + high_lvl_cnter := 0; + end if; + + -- (LSB) Bit stuffing? + if high_lvl_cnter >= 5 then + data_out(0) <= '0'; + + high_lvl_cnter := 0; + offset_pos := 0; + hdlc_state <= s5_sendEOF; + + else + + data_out(0) <= DELIMITER_PACKET(0); + offset_pos := 1; + hdlc_state <= s5_sendEOF; + + end if; + end if; + + end if; + + when s5_sendEOF => + + if offset_pos <= 6 then + data_out(1) <= DELIMITER_PACKET(offset_pos); + data_out(0) <= DELIMITER_PACKET(offset_pos+1); + + offset_pos := offset_pos + 2; + + if offset_pos > 7 then + offset_pos := 0; + hdlc_state <= s0_waitForStart; + end if; + + elsif offset_pos > 6 then + data_out(1) <= DELIMITER_PACKET(7); + data_out(0) <= IDLE_PACKET(0); + + offset_pos := 1; + hdlc_state <= s0_waitForStart; + end if; + + end case; + end if; + end if; + end process; + +end behaviour; +--============================================================================-- +--############################################################################-- +--============================================================================-- \ No newline at end of file diff --git a/vldb/code/GBT-SC/gbtsc_top.vhd b/vldb/code/GBT-SC/gbtsc_top.vhd new file mode 100644 index 0000000..b6a876a --- /dev/null +++ b/vldb/code/GBT-SC/gbtsc_top.vhd @@ -0,0 +1,301 @@ +------------------------------------------------------- +--! @file +--! @author Julian Mendez (CERN - EP-ESE-BE) +--! @date April, 2017 +--! @version 1.0 +--! @brief IC and EC control - TOP level +------------------------------------------------------- + +--! Include the IEEE VHDL standard library +library ieee; +--! Use STD_Logic to define vector types +use ieee.std_logic_1164.all; + +--! Include the work library +library work; +--! Use SCA Package to define specific types (vector arrays) +use work.SCA_PKG.all; + +--! @brief GBTSC_top Entity - TOP Level +--! @details +--! The gbtsc_top module implements the required blocks to carry out Internal (GBTx) +--! and external (SCA) slow control. Its purpose is to handle the communication +--! with up to 41 SCAs and 1 GBTx (max. capability of a GBT link). +entity gbtsc_top is + generic ( + -- IC configuration + g_IC_FIFO_DEPTH : integer := 20; --! Defines the depth of the FIFO used to handle the Internal control (Max. number of words/bytes can be read/write from/to a GBTx) + g_ToLpGBT : integer range 0 to 1 := 0; --! 1 to use LpGBT. Otherwise, it should be 0 + g_LPGBT_VERS : std_logic := '1'; --! Select lpGBT version ('0': 0, '1': 1) + + -- EC configuration + g_SCA_COUNT : integer := 1 --! Defines the maximum number of SCA that can be connected to this module + ); + port ( + -- Clock & reset + tx_clk_i : in std_logic; --! Tx clock (Tx_frameclk_o from GBT-FPGA IP): must be a multiple of the LHC frequency + tx_clk_en : in std_logic := '1'; --! Tx clock enable signal must be used in case of multi-cycle path(tx_clk_i > LHC frequency). By default: always enabled + + rx_clk_i : in std_logic; --! Rx clock (Rx_frameclk_o from GBT-FPGA IP): must be a multiple of the LHC frequency + rx_clk_en : in std_logic := '1'; --! Rx clock enable signal must be used in case of multi-cycle path(rx_clk_i > LHC frequency). By default: always enabled + + rx_reset_i : in std_logic; --! Reset RX datapath + tx_reset_i : in std_logic; --! Reset TX datapath + + -- IC control + tx_start_write_i : in std_logic; --! Request a write config. to the GBTx (IC) + tx_start_read_i : in std_logic; --! Request a read config. to the GBTx (IC) + + -- IC configuration + tx_GBTx_address_i : in std_logic_vector(7 downto 0); --! I2C address of the GBTx + tx_register_addr_i : in std_logic_vector(15 downto 0); --! Address of the first register to be accessed + tx_nb_to_be_read_i : in std_logic_vector(15 downto 0); --! Number of words/bytes to be read (only for read transactions) + + -- IC FIFO control + wr_clk_i : in std_logic; --! Fifo's writing clock + tx_wr_i : in std_logic; --! Request a write operation into the internal FIFO (Data to GBTx) + tx_data_to_gbtx_i : in std_logic_vector(7 downto 0); --! Data to be written into the internal FIFO + + rd_clk_i : in std_logic; + rx_rd_i : in std_logic; --! Request a read operation of the internal FIFO (GBTx reply) + rx_data_from_gbtx_o : out std_logic_vector(7 downto 0); --! Data from the FIFO + + -- IC Status + tx_ready_o : out std_logic; --! IC core ready for a transaction + rx_empty_o : out std_logic; --! Rx FIFO is empty (no reply from GBTx) + + -- SCA control + sca_enable_i : in std_logic_vector((g_SCA_COUNT-1) downto 0); --! Enable flag to select SCAs + start_reset_cmd_i : in std_logic; --! Send a reset command to the enabled SCAs + start_connect_cmd_i : in std_logic; --! Send a connect command to the enabled SCAs + start_command_i : in std_logic; --! Send the command set in input to the enabled SCAs + inject_crc_error : in std_logic; --! Emulate a CRC error + + -- SCA command + tx_address_i : in std_logic_vector(7 downto 0); --! Command: address field (According to the SCA manual) + tx_transID_i : in std_logic_vector(7 downto 0); --! Command: transaction ID field (According to the SCA manual) + tx_channel_i : in std_logic_vector(7 downto 0); --! Command: channel field (According to the SCA manual) + tx_command_i : in std_logic_vector(7 downto 0); --! Command: command field (According to the SCA manual) + tx_data_i : in std_logic_vector(31 downto 0); --! Command: data field (According to the SCA manual) + + rx_received_o : out std_logic_vector((g_SCA_COUNT-1) downto 0); --! Reply received flag (pulse) + rx_address_o : out reg8_arr((g_SCA_COUNT-1) downto 0); --! Reply: address field (According to the SCA manual) + rx_control_o : out reg8_arr((g_SCA_COUNT-1) downto 0); --! Reply: control field (According to the SCA manual) + rx_transID_o : out reg8_arr((g_SCA_COUNT-1) downto 0); --! Reply: transaction ID field (According to the SCA manual) + rx_channel_o : out reg8_arr((g_SCA_COUNT-1) downto 0); --! Reply: channel field (According to the SCA manual) + rx_len_o : out reg8_arr((g_SCA_COUNT-1) downto 0); --! Reply: len field (According to the SCA manual) + rx_error_o : out reg8_arr((g_SCA_COUNT-1) downto 0); --! Reply: error field (According to the SCA manual) + rx_data_o : out reg32_arr((g_SCA_COUNT-1) downto 0); --! Reply: data field (According to the SCA manual) + + -- EC line + ec_data_o : out reg2_arr((g_SCA_COUNT-1) downto 0); --! (TX) Array of bits to be mapped to the TX GBT-Frame + ec_data_i : in reg2_arr((g_SCA_COUNT-1) downto 0); --! (RX) Array of bits to be mapped to the RX GBT-Frame + + -- IC lines + ic_data_o : out std_logic_vector(1 downto 0); --! (TX) Array of bits to be mapped to the TX GBT-Frame (bits 83/84) + ic_data_i : in std_logic_vector(1 downto 0) --! (RX) Array of bits to be mapped to the RX GBT-Frame (bits 83/84) + + ); +end gbtsc_top; + +--! @brief GBTSC_top architecture - TOP Level +--! @details GBTSC_top architecture instantiates the modules used to handle the IC and EC slow control. It maps all of the signal from +--! its entity to the sca_top and ic_top components. No additional logic is added in this block. +architecture behaviour of gbtsc_top is + + -- Signals + signal tx_start_write_s : std_logic; --! Used to simulate a write command request to the GBTx + signal tx_start_read_s : std_logic; --! Used to simulate a read command request to the GBTx + + --! SCA_top component - TOP Level of the SCA-EC module + component sca_top is + generic ( + g_SCA_COUNT : integer := 1 + ); + port ( + tx_clk_i : in std_logic; + tx_clk_en : in std_logic; + + rx_clk_i : in std_logic; + rx_clk_en : in std_logic; + + rx_reset_i : in std_logic; + tx_reset_i : in std_logic; + + enable_i : in std_logic_vector(g_SCA_COUNT-1 downto 0); + start_reset_cmd_i : in std_logic; + start_connect_cmd_i : in std_logic; + start_command_i : in std_logic; + inject_crc_error : in std_logic; + + tx_address_i : in std_logic_vector(7 downto 0); + tx_transID_i : in std_logic_vector(7 downto 0); + tx_channel_i : in std_logic_vector(7 downto 0); + tx_len_i : in std_logic_vector(7 downto 0); + tx_command_i : in std_logic_vector(7 downto 0); + tx_data_i : in std_logic_vector(31 downto 0); + + rx_received_o : out std_logic_vector(g_SCA_COUNT-1 downto 0); + rx_address_o : out reg8_arr(g_SCA_COUNT-1 downto 0); + rx_control_o : out reg8_arr(g_SCA_COUNT-1 downto 0); + rx_transID_o : out reg8_arr(g_SCA_COUNT-1 downto 0); + rx_channel_o : out reg8_arr(g_SCA_COUNT-1 downto 0); + rx_len_o : out reg8_arr(g_SCA_COUNT-1 downto 0); + rx_error_o : out reg8_arr(g_SCA_COUNT-1 downto 0); + rx_data_o : out reg32_arr(g_SCA_COUNT-1 downto 0); + + tx_data_o : out reg2_arr(g_SCA_COUNT-1 downto 0); + rx_data_i : in reg2_arr(g_SCA_COUNT-1 downto 0) + + ); + end component sca_top; + + --! IC_top component - TOP Level of the IC module + component ic_top is + generic ( + g_ToLpGBT : integer range 0 to 1 := 0; + g_FIFO_DEPTH : integer := 20; --! Depth of the internal FIFO used to improve the timming performance + g_LPGBT_VERS : std_logic := '1' --! Select lpGBT version ('0': 0, '1': 1) + ); + port ( + -- Clock and reset + tx_clk_i : in std_logic; --! Tx clock (Tx_frameclk_o from GBT-FPGA IP): must be a multiple of the LHC frequency + tx_clk_en : in std_logic; --! Tx clock enable signal must be used in case of multi-cycle path(tx_clk_i > LHC frequency). By default: always enabled + + rx_clk_i : in std_logic; --! Rx clock (Rx_frameclk_o from GBT-FPGA IP): must be a multiple of the LHC frequency + rx_clk_en : in std_logic; --! Rx clock enable signal must be used in case of multi-cycle path(rx_clk_i > LHC frequency). By default: always enabled + + rx_reset_i : in std_logic; --! Reset RX datapath + tx_reset_i : in std_logic; --! Reset TX datapath + + -- Configuration + tx_GBTx_address_i : in std_logic_vector(7 downto 0); --! I2C address of the GBTx + tx_register_addr_i : in std_logic_vector(15 downto 0); --! Address of the first register to be accessed + tx_nb_to_be_read_i : in std_logic_vector(15 downto 0); --! Number of words/bytes to be read (only for read transactions) + + parity_err_mask_i : in std_logic_vector(7 downto 0); + + -- Internal FIFO + wr_clk_i : in std_logic; --! Fifo's writing clock + tx_wr_i : in std_logic; --! Request a write operation into the internal FIFO (Data to GBTx) + tx_data_to_gbtx_i : in std_logic_vector(7 downto 0); --! Data to be written into the internal FIFO + + rd_clk_i : in std_logic; + rx_rd_i : in std_logic; --! Request a read operation of the internal FIFO (GBTx reply) + rx_data_from_gbtx_o : out std_logic_vector(7 downto 0); --! Data from the FIFO + + -- FSM Control + tx_start_write_i : in std_logic; --! Request a write config. to the GBTx + tx_start_read_i : in std_logic; --! Request a read config. to the GBTx + + -- Status + tx_ready_o : out std_logic; --! IC core ready for a transaction + rx_empty_o : out std_logic; --! Rx FIFO is empty (no reply from GBTx) + + -- IC lines + tx_data_o : out std_logic_vector(1 downto 0); --! (TX) Array of bits to be mapped to the TX GBT-Frame (bits 83/84) + rx_data_i : in std_logic_vector(1 downto 0) --! (RX) Array of bits to be mapped to the RX GBT-Frame (bits 83/84) + + ); + end component ic_top; + +begin --========#### Architecture Body ####========-- + + + --! Instantiation of the SCA_top component + sca_inst: sca_top + generic map( + g_SCA_COUNT => g_SCA_COUNT + ) + port map( + tx_clk_i => tx_clk_i, + tx_clk_en => tx_clk_en, + + rx_clk_i => rx_clk_i, + rx_clk_en => rx_clk_en, + + rx_reset_i => rx_reset_i, + tx_reset_i => tx_reset_i, + + enable_i => sca_enable_i, + start_reset_cmd_i => start_reset_cmd_i, + start_connect_cmd_i => start_connect_cmd_i, + start_command_i => start_command_i, + inject_crc_error => inject_crc_error, + + tx_address_i => tx_address_i, + tx_transID_i => tx_transID_i, + tx_channel_i => tx_channel_i, + tx_len_i => x"04", -- tx_len_i, -- Fixed (BUG) + tx_command_i => tx_command_i, + tx_data_i => tx_data_i, + + rx_received_o => rx_received_o, + rx_address_o => rx_address_o, + rx_control_o => rx_control_o, + rx_transID_o => rx_transID_o, + rx_channel_o => rx_channel_o, + rx_len_o => rx_len_o, + rx_error_o => rx_error_o, + rx_data_o => rx_data_o, + + tx_data_o => ec_data_o, + rx_data_i => ec_data_i + + ); + + tx_start_write_s <= tx_start_write_i ; + tx_start_read_s <= tx_start_read_i ; + + --! Instantiation of the IC_top component + ic_inst: ic_top + generic map( + g_ToLpGBT => g_ToLpGBT, + g_FIFO_DEPTH => g_IC_FIFO_DEPTH, + g_LPGBT_VERS => g_LPGBT_VERS + ) + port map( + + -- Clock and reset + tx_clk_i => tx_clk_i, + tx_clk_en => tx_clk_en, + + rx_clk_i => rx_clk_i, + rx_clk_en => rx_clk_en, + + rx_reset_i => rx_reset_i, + tx_reset_i => tx_reset_i, + + -- Configuration + tx_GBTx_address_i => tx_GBTx_address_i, + tx_register_addr_i => tx_register_addr_i, + tx_nb_to_be_read_i => tx_nb_to_be_read_i, + + parity_err_mask_i => (others => '0'), + + -- Internal FIFO + wr_clk_i => wr_clk_i, + tx_wr_i => tx_wr_i, + tx_data_to_gbtx_i => tx_data_to_gbtx_i, + + rd_clk_i => rd_clk_i, + rx_rd_i => rx_rd_i, + rx_data_from_gbtx_o => rx_data_from_gbtx_o, + + -- FSM Control + tx_start_write_i => tx_start_write_s, + tx_start_read_i => tx_start_read_s, + + -- Status + tx_ready_o => tx_ready_o, + rx_empty_o => rx_empty_o, + + -- IC lines + tx_data_o => ic_data_o, + rx_data_i => ic_data_i + ); + +end behaviour; +--============================================================================-- +--############################################################################-- +--============================================================================-- \ No newline at end of file diff --git a/vldb/code/gbt_core.vhd b/vldb/code/gbt_core.vhd new file mode 100644 index 0000000..a7d33b6 --- /dev/null +++ b/vldb/code/gbt_core.vhd @@ -0,0 +1,265 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.trb_net_std.all; + + +entity gbt_core is + port( + CLK_SYS : in std_logic; + CLK : in std_logic; + RESET : in std_logic; + + BUS_RX : in CTRLBUS_RX; + BUS_TX : out CTRLBUS_TX; + + ELINK_RX : in std_logic; + ELINK_TX : out std_logic + ); +end entity; + + +architecture arch of gbt_core is + + -- Clock & reset + signal gbtsc_tx_clk_en : std_logic := '0'; --! Tx clock enable signal must be used in case of multi-cycle path(tx_clk_i > LHC frequency). By default: always enabled + signal gbtsc_rx_clk_en : std_logic := '0'; --! Rx clock enable signal must be used in case of multi-cycle path(rx_clk_i > LHC frequency). By default: always enabled + + -- SCA control + signal gbtsc_sca_enable_i : std_logic := '1'; --! Enable flag to select SCAs + signal gbtsc_start_reset_cmd_i : std_logic := '0'; --! Send a reset command to the enabled SCAs + signal gbtsc_start_connect_cmd_i : std_logic := '0'; --! Send a connect command to the enabled SCAs + signal gbtsc_start_command_i : std_logic := '0'; --! Send the command set in input to the enabled SCAs + signal gbtsc_start_reset_cmd_raw :std_logic := '0'; + signal gbtsc_start_connect_cmd_raw :std_logic := '0'; + signal gbtsc_start_command_raw :std_logic := '0'; + signal gbtsc_reset_go : std_logic := '0'; + signal gbtsc_connect_go : std_logic := '0'; + signal gbtsc_go : std_logic := '0'; + -- SCA command + signal gbtsc_tx_address_i : std_logic_vector(7 downto 0) := x"00"; --! Command: address field (According to the SCA manual) + signal gbtsc_tx_transID_i : std_logic_vector(7 downto 0) := x"01"; --! Command: transaction ID field (According to the SCA manual) + signal gbtsc_tx_channel_i : std_logic_vector(7 downto 0) := x"00"; --! Command: channel field (According to the SCA manual) + signal gbtsc_tx_command_i : std_logic_vector(7 downto 0) := x"02"; --! Command: command field (According to the SCA manual) + signal gbtsc_tx_data_i : std_logic_vector(31 downto 0) := x"0000FF00"; --! Command: data field (According to the SCA manual) + + signal gbtsc_rx_received_o : std_logic := '0'; --! Reply received flag (pulse) + signal gbtsc_rx_address_o : std_logic_vector(7 downto 0); --! Reply: address field (According to the SCA manual) + signal gbtsc_rx_control_o : std_logic_vector(7 downto 0); --! Reply: control field (According to the SCA manual) + signal gbtsc_rx_transID_o : std_logic_vector(7 downto 0); --! Reply: transaction ID field (According to the SCA manual) + signal gbtsc_rx_channel_o : std_logic_vector(7 downto 0); --! Reply: channel field (According to the SCA manual) + signal gbtsc_rx_len_o : std_logic_vector(7 downto 0); --! Reply: len field (According to the SCA manual) + signal gbtsc_rx_error_o : std_logic_vector(7 downto 0); --! Reply: error field (According to the SCA manual) + signal gbtsc_rx_data_o : std_logic_vector(31 downto 0); --! Reply: data field (According to the SCA manual) + + -- EC line + signal hdlc_from_gbtsc : std_logic_vector(1 downto 0) := "11"; --! (TX) Array of bits to be mapped to the TX GBT-Frame + signal hdlc_to_gbtsc : std_logic_vector(1 downto 0) := "11"; --! (RX) Array of bits to be mapped to the RX GBT-Frame + +begin + + THE_GBTSC_TOP : entity work.gbtsc_top + generic map( + -- IC configuration + g_IC_FIFO_DEPTH => 20, --! Defines the depth of the FIFO used to handle the Internal control (Max. number of words/bytes can be read/write from/to a GBTx) + + -- EC configuration + g_SCA_COUNT => 1 --! Defines the maximum number of SCA that can be connected to this module + ) + port map( + + -- Clock & reset + tx_clk_i => CLK, -- gbtsc_tx_clk_i, --! Tx clock (Tx_frameclk_o from GBT-FPGA IP): must be a multiple of the LHC frequency + tx_clk_en => gbtsc_tx_clk_en, --! Tx clock enable signal must be used in case of multi-cycle path(tx_clk_i > LHC frequency). By default: always enabled + tx_reset_i => RESET, -- gbtsc_tx_reset_i, --! Reset TX datapath + + rx_clk_i => CLK, -- gbtsc_rx_clk_i, --! Rx clock (Rx_frameclk_o from GBT-FPGA IP): must be a multiple of the LHC frequency + rx_clk_en => gbtsc_rx_clk_en, --! Rx clock enable signal must be used in case of multi-cycle path(rx_clk_i > LHC frequency). By default: always enabled + rx_reset_i => RESET, -- gbtsc_rx_reset_i, --! Reset RX datapath + + -- IC control + tx_start_write_i => '0', -- gbtsc_tx_start_write_i, --! Request a write config. to the GBTx (IC) + tx_start_read_i => '0', -- gbtsc_tx_start_read_i, --! Request a read config. to the GBTx (IC) + + -- IC configuration + tx_GBTx_address_i => (others => '0'), -- gbtsc_tx_GBTx_address_i, --! I2C address of the GBTx + tx_register_addr_i => (others => '0'), -- gbtsc_tx_register_addr_i, --! Address of the first register to be accessed + tx_nb_to_be_read_i => (others => '0'), -- gbtsc_tx_nb_to_be_read_i, --! Number of words/bytes to be read (only for read transactions) + + -- IC FIFO control + wr_clk_i => CLK, --! Fifo's writing clock + tx_wr_i => '0', -- gbtsc_tx_wr_i, --! Request a write operation into the internal FIFO (Data to GBTx) + tx_data_to_gbtx_i => (others => '0'), -- gbtsc_tx_data_to_gbtx_i, --! Data to be written into the internal FIFO + + rd_clk_i => CLK, + rx_rd_i => '0', -- gbtsc_rx_rd_i, --! Request a read operation of the internal FIFO (GBTx reply) + rx_data_from_gbtx_o => open, -- gbtsc_rx_data_from_gbtx_o, --! Data from the FIFO + + -- IC Status + tx_ready_o => open, -- gbtsc_tx_ready_o, --! IC core ready for a transaction + rx_empty_o => open, -- gbtsc_rx_empty_o, --! Rx FIFO is empty (no reply from GBTx) + + -- SCA control + sca_enable_i(0) => gbtsc_sca_enable_i, --! Enable flag to select SCAs + start_reset_cmd_i => gbtsc_start_reset_cmd_i, --! Send a reset command to the enabled SCAs + start_connect_cmd_i => gbtsc_start_connect_cmd_i, --! Send a connect command to the enabled SCAs + start_command_i => gbtsc_start_command_i, --! Send the command set in input to the enabled SCAs + inject_crc_error => '0', --! Emulate a CRC error + + -- SCA command + tx_address_i => gbtsc_tx_address_i, --! Command: address field (According to the SCA manual) + tx_transID_i => gbtsc_tx_transID_i, --! Command: transaction ID field (According to the SCA manual) + tx_channel_i => gbtsc_tx_channel_i, --! Command: channel field (According to the SCA manual) + tx_command_i => gbtsc_tx_command_i, --! Command: command field (According to the SCA manual) + tx_data_i => gbtsc_tx_data_i, --! Command: data field (According to the SCA manual) + + rx_received_o(0) => gbtsc_rx_received_o, --! Reply: received flag (pulse) + rx_address_o(0) => gbtsc_rx_address_o, --! Reply: address field (According to the SCA manual) + rx_control_o(0) => gbtsc_rx_control_o, --! Reply: control field (According to the SCA manual) + rx_transID_o(0) => gbtsc_rx_transID_o, --! Reply: transaction ID field (According to the SCA manual) + rx_channel_o(0) => gbtsc_rx_channel_o, --! Reply: channel field (According to the SCA manual) + rx_len_o(0) => gbtsc_rx_len_o, --! Reply: len field (According to the SCA manual) + rx_error_o(0) => gbtsc_rx_error_o, --! Reply: error field (According to the SCA manual) + rx_data_o(0) => gbtsc_rx_data_o, --! Reply: data field (According to the SCA manual) + + -- EC line + ec_data_o(0) => hdlc_from_gbtsc, --! (TX) Array of bits to be mapped to the TX GBT-Frame + ec_data_i(0) => hdlc_to_gbtsc, --! (RX) Array of bits to be mapped to the RX GBT-Frame + + -- IC lines + ic_data_o => open, --! (TX) Array of bits to be mapped to the TX GBT-Frame (bits 83/84) + ic_data_i => "00" --! (RX) Array of bits to be mapped to the RX GBT-Frame (bits 83/84) + ); + + -- -- shift signals to the next high enable + -- PROC_SHIFT_TO_EN : process + -- variable reg_res : std_logic_vector(1 downto 0) := "00"; + -- variable reg_con : std_logic_vector(1 downto 0) := "00"; + -- variable reg_cmd : std_logic_vector(1 downto 0) := "00"; + -- begin + -- wait until rising_edge(CLK); + -- reg_res := reg_res(0) & gbtsc_start_reset_cmd_raw; + -- reg_con := reg_con(0) & gbtsc_start_connect_cmd_raw; + -- reg_cmd := reg_cmd(0) & gbtsc_start_command_raw; + -- gbtsc_start_reset_cmd_i <= (reg_res(0) and not gbtsc_tx_clk_en ) or (reg_res(1) and not gbtsc_tx_clk_en); + -- gbtsc_start_connect_cmd_i <= (reg_con(0) and not gbtsc_tx_clk_en ) or (reg_con(1) and not gbtsc_tx_clk_en); + -- gbtsc_start_command_i <= (reg_cmd(0) and not gbtsc_tx_clk_en ) or (reg_cmd(1) and not gbtsc_tx_clk_en); + -- end process; + + -- HDLC serializer + hdlcser_proc: process(CLK) + begin + if rising_edge(CLK) then + gbtsc_tx_clk_en <= gbtsc_tx_clk_en xor '1'; + if gbtsc_tx_clk_en = '1' then + ELINK_TX <= hdlc_from_gbtsc(0); + elsif gbtsc_tx_clk_en = '0' then + ELINK_TX <= hdlc_from_gbtsc(1); + end if; + end if; + end process; + + -- HDLC deserializer + hdlcdes_proc: process(CLK) + begin + if rising_edge(CLK) then + gbtsc_rx_clk_en <= gbtsc_rx_clk_en xor '1'; + if gbtsc_rx_clk_en = '1' then + hdlc_to_gbtsc(1) <= ELINK_RX; + elsif gbtsc_rx_clk_en = '0' then + hdlc_to_gbtsc(0) <= ELINK_RX; + end if; + end if; + end process; + + PROC_GBTSCA_REG_CMDS : process + begin + wait until rising_edge(CLK_SYS); + BUS_TX.ack <= '0'; + BUS_TX.unknown <= '0'; + BUS_TX.nack <= '0'; + BUS_TX.data <= (others => '0'); + -- reset start flags + gbtsc_reset_go <= '0'; + gbtsc_connect_go <= '0'; + gbtsc_go <= '0'; + + if BUS_RX.write = '1' then + BUS_TX.ack <= '1'; + + if BUS_RX.addr(3 downto 0) = x"0" then + gbtsc_tx_address_i <= BUS_RX.data(7 downto 0); + -- gbtsc_sca_enable_i <= BUS_RX.data(8); + gbtsc_reset_go <= BUS_RX.data(9); + gbtsc_connect_go <= BUS_RX.data(10); + gbtsc_go <= BUS_RX.data(11); + elsif BUS_RX.addr(3 downto 0) = x"1" then + gbtsc_tx_transID_i <= BUS_RX.data(7 downto 0); + gbtsc_tx_channel_i <= BUS_RX.data(15 downto 8); + -- gbtsc_tx_len_i <= BUS_RX.data(23 downto 16); + gbtsc_tx_command_i <= BUS_RX.data(31 downto 24); + elsif BUS_RX.addr(3 downto 0) = x"2" then + gbtsc_tx_data_i <= BUS_RX.data(31 downto 0); + else + BUS_TX.ack <= '0'; + BUS_TX.unknown <= '1'; + end if; + + elsif BUS_RX.read = '1' and gbtsc_rx_received_o = '1' then + BUS_TX.ack <= '1'; + + if BUS_RX.addr(3 downto 0) = x"0" then + BUS_TX.data(7 downto 0) <= gbtsc_rx_address_o; + elsif BUS_RX.addr(3 downto 0) = x"1" then + BUS_TX.data( 7 downto 0 ) <= gbtsc_rx_transID_o; + BUS_TX.data(15 downto 8 ) <= gbtsc_rx_channel_o; + BUS_TX.data(23 downto 16) <= gbtsc_rx_len_o; + elsif BUS_RX.addr(3 downto 0) = x"2" then + BUS_TX.data(31 downto 0) <= gbtsc_rx_data_o; + elsif BUS_RX.addr(3 downto 0) = x"3" then + BUS_TX.data(7 downto 0) <= gbtsc_rx_control_o; + BUS_TX.data(15 downto 8) <= gbtsc_rx_error_o; + else + BUS_TX.ack <= '0'; + BUS_TX.unknown <= '1'; + end if; + + end if; + end process; + + + + THE_CMD_SYNC : entity work.pulse_sync + port map( + CLK_A_IN => CLK_SYS, + RESET_A_IN => RESET, + PULSE_A_IN => gbtsc_go, + CLK_B_IN => gbtsc_tx_clk_en, + RESET_B_IN => RESET, + PULSE_B_OUT => gbtsc_start_command_i + ); + + THE_RESET_SYNC : entity work.pulse_sync + port map( + CLK_A_IN => CLK_SYS, + RESET_A_IN => RESET, + PULSE_A_IN => gbtsc_reset_go, + CLK_B_IN => gbtsc_tx_clk_en, + RESET_B_IN => RESET, + PULSE_B_OUT => gbtsc_start_reset_cmd_i + ); + + THE_CONNECT_SYNC : entity work.pulse_sync + port map( + CLK_A_IN => CLK_SYS, + RESET_A_IN => RESET, + PULSE_A_IN => gbtsc_connect_go, + CLK_B_IN => gbtsc_tx_clk_en, + RESET_B_IN => RESET, + PULSE_B_OUT => gbtsc_start_connect_cmd_i + ); + + +end architecture; -- 2.43.0