URL
https://opencores.org/ocsvn/pcie_mini/pcie_mini/trunk
Subversion Repositories pcie_mini
Compare Revisions
- This comparison shows the changes necessary to convert path
/pcie_mini/trunk/main_sources/oldversions
- from Rev 10 to Rev 11
- ↔ Reverse comparison
Rev 10 → Rev 11
/xilinx_pcie2wb_v1.2.vhd
0,0 → 1,1448
---------------------------------------------------------------------------------- |
-- Company: |
-- Engineer: Istvan Nagy, buenos@freemail.hu |
-- |
-- Create Date: 05/30/2010 |
-- Modify date: 08/10/2012 |
-- Design Name: pcie_mini |
-- Module Name: xilinx_pcie2wb - Behavioral |
-- Version: 1.2 |
-- Project Name: |
-- Target Devices: Xilinx Series-5/6/7 FPGAs |
-- Tool versions: ISE-DS 12.1 |
-- Description: |
-- PCI-express endpoint block, transaction layer logic and back-end logic. The main |
-- purpose of this file is to make a useable back-end interface and handle flow control |
-- for the xilinx auto-generated PCIe endpoint IP. |
-- The PCIe endpoint implements one 256MByte memory BAR (Base Address Register). |
-- This 256MBytes size is set up in the core config, and also hardcoded in this |
-- file (search for: "256MBytes"). |
-- This 1 BAR is implemented as a Wishbone master interface with byte addressing, |
-- where address [x:2] shows DWORD address, while sel[3:0] decodes the 2 LSBs. |
-- ADDRESSES ARE BYTE ADDRESSES. |
-- The lower address bits are usually zero, so the slave (MCB) has to select bytes based |
-- on the byte select signals: sel[3:0]. The output address of the core contails the 2 |
-- LSBs as well. The core was only tested with 32-bit accesses, byte-wide might work or not. |
-- The TLP logic is capable of handling up to 1k bytes (256 DWORDs) payload data in a |
-- single PCIe transaction, and can handle only one request at a time. If a new request |
-- is arriving while processing the previous one (e.g. getting the data from a wishbone |
-- read), then the state machine will not process it immediately, or it will hang. So |
-- the user software has to wait for the previous read completion before issueing a new |
-- request. The multiple DWORDs are handled separately by the WB statemachine. |
-- Performance: WishBone bus: 62.5MHz, 32bit, 2clk/access -> 125MBytes/sec. The maximum |
-- data throughput can be achieved when using the maximum data payload (block). |
-- The core uses INTA wirtual wire to signal interrupts. |
-- |
-- x1 PCIe, legacy endpoint, uses a 100MHz ref clock. The generated core had to |
-- be edited manually to support 100MHz, as per Xilinx AR#33761. |
-- |
-- Dependencies: The CoreGenerator's configured PCIe core is included. |
-- If we generate a new pcie endpoint, then copy the new files from the source |
-- directory into the project's directory, and copy the generic section of the "pcie" |
-- from the file: xilinx_pcie_1_1_ep_s6.vhd, into this file. |
-- Synthesis: Set the "FSM Encoding Algorithm" to "user". |
-- |
-- Revision: |
-- Revision 1.0 - File Created by Istvan Nagy |
-- Revision 1.1 - some fixes by Istvan Nagy |
-- Revision 1.2 - interrupt fix by Stephen Battazzo |
-- |
---------------------------------------------------------------------------------- |
|
library IEEE; |
use IEEE.STD_LOGIC_1164.ALL; |
use IEEE.STD_LOGIC_ARITH.ALL; |
use IEEE.STD_LOGIC_UNSIGNED.ALL; |
|
-- Uncomment the following library declaration if instantiating |
-- any Xilinx primitives in this code. |
library UNISIM; |
use UNISIM.VComponents.all; |
|
|
|
entity xilinx_pcie2wb is |
Port ( --FPGA PINS(EXTERNAL): |
pci_exp_txp : out std_logic; |
pci_exp_txn : out std_logic; |
pci_exp_rxp : in std_logic; |
pci_exp_rxn : in std_logic; |
sys_clk_n : in std_logic; |
sys_clk_p : in std_logic; |
sys_reset_n : in std_logic; |
--ON CHIP PORTS: |
--DATA BUS for BAR0 (wishbone): |
pcie_bar0_wb_data_o : out std_logic_vector(31 downto 0); |
pcie_bar0_wb_data_i : in std_logic_vector(31 downto 0); |
pcie_bar0_wb_addr_o : out std_logic_vector(27 downto 0); |
pcie_bar0_wb_cyc_o : out std_logic; |
pcie_bar0_wb_stb_o : out std_logic; |
pcie_bar0_wb_wr_o : out std_logic; |
pcie_bar0_wb_ack_i : in std_logic; |
pcie_bar0_wb_clk_o : out std_logic; --62.5MHz |
pcie_bar0_wb_sel_o : out std_logic_vector(3 downto 0); |
--OTHER: |
pcie_irq : in std_logic; |
pcie_resetout : out std_logic --active high |
); |
end xilinx_pcie2wb; |
|
|
|
|
architecture Behavioral of xilinx_pcie2wb is |
|
|
|
|
-- Internal Signals ------------------------------------------------------------ |
--SIGNAL dummy : std_logic_vector(15 downto 0); --write data bus |
SIGNAL cfg_do : std_logic_vector(31 downto 0); |
SIGNAL cfg_rd_wr_done_n : std_logic; |
SIGNAL cfg_dwaddr : std_logic_vector(9 downto 0); |
SIGNAL cfg_rd_en_n : std_logic; |
SIGNAL cfg_err_ur_n : std_logic; |
SIGNAL cfg_err_cor_n : std_logic; |
SIGNAL cfg_err_ecrc_n : std_logic; |
SIGNAL cfg_err_cpl_timeout_n : std_logic; |
SIGNAL cfg_err_cpl_abort_n : std_logic; |
SIGNAL cfg_err_posted_n : std_logic; |
SIGNAL cfg_err_locked_n : std_logic; |
SIGNAL cfg_err_tlp_cpl_header : std_logic_vector(47 downto 0); |
SIGNAL cfg_err_cpl_rdy_n : std_logic; |
SIGNAL cfg_interrupt_n : std_logic; |
SIGNAL cfg_interrupt_rdy_n : std_logic; |
SIGNAL cfg_interrupt_assert_n : std_logic; |
SIGNAL cfg_interrupt_do : std_logic_vector(7 downto 0); |
SIGNAL cfg_interrupt_di : std_logic_vector(7 downto 0); |
SIGNAL cfg_interrupt_mmenable : std_logic_vector(2 downto 0); |
SIGNAL cfg_interrupt_msienable : std_logic; |
SIGNAL cfg_turnoff_ok_n : std_logic; |
SIGNAL cfg_to_turnoff_n : std_logic; |
SIGNAL cfg_pm_wake_n : std_logic; |
SIGNAL cfg_pcie_link_state_n : std_logic_vector(2 downto 0); |
SIGNAL cfg_trn_pending_n : std_logic; |
SIGNAL cfg_dsn : std_logic_vector(63 downto 0); |
SIGNAL cfg_bus_number : std_logic_vector(7 downto 0); |
SIGNAL cfg_device_number : std_logic_vector(4 downto 0); |
SIGNAL cfg_function_number : std_logic_vector(2 downto 0); |
SIGNAL cfg_status : std_logic_vector(15 downto 0); |
SIGNAL cfg_command : std_logic_vector(15 downto 0); |
SIGNAL cfg_dstatus : std_logic_vector(15 downto 0); |
SIGNAL cfg_dcommand : std_logic_vector(15 downto 0); |
SIGNAL cfg_lstatus : std_logic_vector(15 downto 0); |
SIGNAL cfg_lcommand : std_logic_vector(15 downto 0); |
-- System Interface |
SIGNAL sys_clk : std_logic; |
SIGNAL trn_clk : std_logic; |
SIGNAL trn_reset_n : std_logic; |
SIGNAL received_hot_reset : std_logic; |
-- Transaction (TRN) Interface |
SIGNAL trn_lnk_up_n : std_logic; |
-- data interface Tx |
SIGNAL trn_td : std_logic_vector(31 downto 0); |
SIGNAL trn_tsof_n : std_logic; |
SIGNAL trn_teof_n : std_logic; |
SIGNAL trn_tsrc_rdy_n : std_logic; |
SIGNAL trn_tdst_rdy_n : std_logic; |
SIGNAL trn_terr_drop_n : std_logic; |
SIGNAL trn_tsrc_dsc_n : std_logic; |
SIGNAL trn_terrfwd_n : std_logic; |
SIGNAL trn_tbuf_av : std_logic_vector(5 downto 0); |
SIGNAL trn_tstr_n : std_logic; |
SIGNAL trn_tcfg_req_n : std_logic; |
SIGNAL trn_tcfg_gnt_n : std_logic; |
-- data interface Rx |
SIGNAL trn_rd : std_logic_vector(31 downto 0); |
SIGNAL trn_rsof_n : std_logic; |
SIGNAL trn_reof_n : std_logic; |
SIGNAL trn_rsrc_rdy_n : std_logic; |
SIGNAL trn_rsrc_dsc_n : std_logic; |
SIGNAL trn_rdst_rdy_n : std_logic; |
SIGNAL trn_rerrfwd_n : std_logic; |
SIGNAL trn_rnp_ok_n : std_logic; |
SIGNAL trn_rbar_hit_n : std_logic_vector(6 downto 0); |
-- flow control |
SIGNAL trn_fc_sel : std_logic_vector(2 downto 0); |
SIGNAL trn_fc_nph : std_logic_vector(7 downto 0); |
SIGNAL trn_fc_npd : std_logic_vector(11 downto 0); |
SIGNAL trn_fc_ph : std_logic_vector(7 downto 0); |
SIGNAL trn_fc_pd : std_logic_vector(11 downto 0); |
SIGNAL trn_fc_cplh : std_logic_vector(7 downto 0); |
SIGNAL trn_fc_cpld : std_logic_vector(11 downto 0); |
|
SIGNAL start_read_wb0 : std_logic; |
SIGNAL start_write_wb0 : std_logic; |
SIGNAL wb_transaction_complete : std_logic; |
SIGNAL pcie_bar0_wb_data_i_latched : std_logic_vector(31 downto 0); |
SIGNAL pcie_bar0_wb_data_o_feed : std_logic_vector(31 downto 0); |
SIGNAL pcie_bar0_wb_addr_o_feed : std_logic_vector(27 downto 0); |
SIGNAL pcie_bar0_wb_sel_o_feed : std_logic_vector(3 downto 0); |
SIGNAL start_read_wb1 : std_logic; |
SIGNAL start_write_wb1 : std_logic; |
SIGNAL rd_data_ready_wb1 : std_logic; |
|
SIGNAL pcie_just_received_a_new_tlp : std_logic ; |
SIGNAL pcie_start_reading_rx_tlp : std_logic ; |
SIGNAL pcie_there_is_a_new_tlp_to_transmit : std_logic ; |
SIGNAL rxtlp_decodedaddress : std_logic_vector(31 downto 0); |
SIGNAL tlp_payloadsize_dwords : std_logic_vector(7 downto 0); |
SIGNAL rxtlp_firstdw_be : std_logic_vector(3 downto 0); |
SIGNAL rxtlp_lastdw_be : std_logic_vector(3 downto 0); |
SIGNAL rxtlp_requesterid : std_logic_vector(15 downto 0); |
SIGNAL tlp_state : std_logic_vector(7 downto 0); |
SIGNAL tlp_state_copy : std_logic_vector(7 downto 0); |
SIGNAL rxtlp_data_0 : std_logic_vector(31 downto 0); |
SIGNAL rxtlp_data_1 : std_logic_vector(31 downto 0); |
SIGNAL rxtlp_data_2 : std_logic_vector(31 downto 0); |
SIGNAL rxtlp_data_3 : std_logic_vector(31 downto 0); |
SIGNAL rxtlp_data_4 : std_logic_vector(31 downto 0); |
SIGNAL rxtlp_data_5 : std_logic_vector(31 downto 0); |
SIGNAL rxtlp_data_6 : std_logic_vector(31 downto 0); |
SIGNAL rxtlp_data_7 : std_logic_vector(31 downto 0); |
SIGNAL txtlp_data_0 : std_logic_vector(31 downto 0); |
SIGNAL txtlp_data_1 : std_logic_vector(31 downto 0); |
SIGNAL txtlp_data_2 : std_logic_vector(31 downto 0); |
SIGNAL txtlp_data_3 : std_logic_vector(31 downto 0); |
SIGNAL txtlp_data_4 : std_logic_vector(31 downto 0); |
SIGNAL txtlp_data_5 : std_logic_vector(31 downto 0); |
SIGNAL txtlp_data_6 : std_logic_vector(31 downto 0); |
SIGNAL txtlp_data_7 : std_logic_vector(31 downto 0); |
SIGNAL pcie_tlp_tx_complete : std_logic; |
|
--this signal added by StBa, AAC Microtec |
SIGNAL irq_prohibit : std_logic; |
|
SIGNAL pcieirq_state : std_logic_vector(7 downto 0); |
SIGNAL txtrn_counter : std_logic_vector(7 downto 0); |
SIGNAL trn_rx_counter : std_logic_vector(7 downto 0); |
SIGNAL cfg_completer_id : std_logic_vector(15 downto 0); |
SIGNAL wb0_state : std_logic_vector(7 downto 0); |
SIGNAL epif_tx_state : std_logic_vector(7 downto 0); |
SIGNAL epif_rx_state : std_logic_vector(7 downto 0); |
SIGNAL bit10 : std_logic_vector(1 downto 0); |
|
SIGNAL bram_rxtlp_we : std_logic_vector(0 downto 0); |
SIGNAL bram_rxtlp_writeaddress : std_logic_vector(31 downto 0); |
SIGNAL bram_rxtlp_writedata : std_logic_vector(31 downto 0); |
SIGNAL bram_rxtlp_readaddress : std_logic_vector(31 downto 0); |
SIGNAL bram_rxtlp_readdata : std_logic_vector(31 downto 0); |
SIGNAL bram_txtlp_we : std_logic_vector(0 downto 0); |
SIGNAL bram_txtlp_writeaddress : std_logic_vector(8 downto 0); |
SIGNAL bram_txtlp_writedata : std_logic_vector(31 downto 0); |
SIGNAL bram_txtlp_readaddress : std_logic_vector(31 downto 0); |
SIGNAL bram_txtlp_readdata : std_logic_vector(31 downto 0); |
|
SIGNAL tlp_datacount : std_logic_vector(7 downto 0); |
--SIGNAL bram_rxtlp_firstdata_address : std_logic_vector(8 downto 0); |
SIGNAL rxtlp_header_dw1 : std_logic_vector(31 downto 0); |
SIGNAL rxtlp_header_dw2 : std_logic_vector(31 downto 0); |
SIGNAL rxtlp_header_dw3 : std_logic_vector(31 downto 0); |
SIGNAL rxtlp_header_dw4 : std_logic_vector(31 downto 0); |
SIGNAL flag1 : std_logic; |
SIGNAL rxdw1_23_0 : std_logic_vector(23 downto 0); |
SIGNAL pcie_rxtlp_tag : std_logic_vector(7 downto 0); |
SIGNAL pciewb_localreset_n : std_logic; |
SIGNAL cfg_interrupt_assert_n_1 : std_logic; |
SIGNAL trn_tsrc_rdy_n_1 : std_logic; |
SIGNAL trn_tsof_n1 : std_logic; |
SIGNAL rcompl_bytecount_field : std_logic_vector(9 downto 0); |
SIGNAL rxstm_readytoroll : std_logic; |
SIGNAL tlpstm_isin_idle : std_logic; |
|
|
|
|
|
-- COMPONENT DECLARATIONS (introducing the IPs) -------------------------------- |
|
--this is the pcie endpoint core from coregenerator. |
--Core name: Xilinx Spartan-6 Integrated |
--Block for PCI Express |
--Version: 1.2 |
--Release Date: September 16, 2009. ISE DS 11.4 |
component pcie is |
generic ( |
TL_TX_RAM_RADDR_LATENCY : integer := 0; |
TL_TX_RAM_RDATA_LATENCY : integer := 2; |
TL_RX_RAM_RADDR_LATENCY : integer := 0; |
TL_RX_RAM_RDATA_LATENCY : integer := 2; |
TL_RX_RAM_WRITE_LATENCY : integer := 0; |
VC0_TX_LASTPACKET : integer := 14; |
VC0_RX_RAM_LIMIT : bit_vector := x"7FF"; |
VC0_TOTAL_CREDITS_PH : integer := 32; |
VC0_TOTAL_CREDITS_PD : integer := 211; |
VC0_TOTAL_CREDITS_NPH : integer := 8; |
VC0_TOTAL_CREDITS_CH : integer := 40; |
VC0_TOTAL_CREDITS_CD : integer := 211; |
VC0_CPL_INFINITE : boolean := TRUE; |
BAR0 : bit_vector := x"F0000000"; |
BAR1 : bit_vector := x"00000000"; |
BAR2 : bit_vector := x"00000000"; |
BAR3 : bit_vector := x"00000000"; |
BAR4 : bit_vector := x"00000000"; |
BAR5 : bit_vector := x"00000000"; |
EXPANSION_ROM : bit_vector := "0000000000000000000000"; |
DISABLE_BAR_FILTERING : boolean := FALSE; |
DISABLE_ID_CHECK : boolean := FALSE; |
TL_TFC_DISABLE : boolean := FALSE; |
TL_TX_CHECKS_DISABLE : boolean := FALSE; |
USR_CFG : boolean := FALSE; |
USR_EXT_CFG : boolean := FALSE; |
DEV_CAP_MAX_PAYLOAD_SUPPORTED : integer := 2; |
CLASS_CODE : bit_vector := x"068000"; |
CARDBUS_CIS_POINTER : bit_vector := x"00000000"; |
PCIE_CAP_CAPABILITY_VERSION : bit_vector := x"1"; |
PCIE_CAP_DEVICE_PORT_TYPE : bit_vector := x"1"; |
PCIE_CAP_SLOT_IMPLEMENTED : boolean := FALSE; |
PCIE_CAP_INT_MSG_NUM : bit_vector := "00000"; |
DEV_CAP_PHANTOM_FUNCTIONS_SUPPORT : integer := 0; |
DEV_CAP_EXT_TAG_SUPPORTED : boolean := FALSE; |
DEV_CAP_ENDPOINT_L0S_LATENCY : integer := 7; |
DEV_CAP_ENDPOINT_L1_LATENCY : integer := 7; |
SLOT_CAP_ATT_BUTTON_PRESENT : boolean := FALSE; |
SLOT_CAP_ATT_INDICATOR_PRESENT : boolean := FALSE; |
SLOT_CAP_POWER_INDICATOR_PRESENT : boolean := FALSE; |
DEV_CAP_ROLE_BASED_ERROR : boolean := TRUE; |
LINK_CAP_ASPM_SUPPORT : integer := 1; |
--LINK_CAP_L0S_EXIT_LATENCY : integer := 7; |
--LINK_CAP_L1_EXIT_LATENCY : integer := 7; |
LL_ACK_TIMEOUT : bit_vector := x"0000"; |
LL_ACK_TIMEOUT_EN : boolean := FALSE; |
--LL_REPLAY_TIMEOUT : bit_vector := x"0204"; |
LL_REPLAY_TIMEOUT : bit_vector := x"0000"; |
LL_REPLAY_TIMEOUT_EN : boolean := FALSE; |
MSI_CAP_MULTIMSGCAP : integer := 0; |
MSI_CAP_MULTIMSG_EXTENSION : integer := 0; |
LINK_STATUS_SLOT_CLOCK_CONFIG : boolean := FALSE; |
PLM_AUTO_CONFIG : boolean := FALSE; |
FAST_TRAIN : boolean := FALSE; |
ENABLE_RX_TD_ECRC_TRIM : boolean := FALSE; |
DISABLE_SCRAMBLING : boolean := FALSE; |
PM_CAP_VERSION : integer := 3; |
PM_CAP_PME_CLOCK : boolean := FALSE; |
PM_CAP_DSI : boolean := FALSE; |
PM_CAP_AUXCURRENT : integer := 0; |
PM_CAP_D1SUPPORT : boolean := TRUE; |
PM_CAP_D2SUPPORT : boolean := TRUE; |
PM_CAP_PMESUPPORT : bit_vector := x"0F"; |
PM_DATA0 : bit_vector := x"04"; |
PM_DATA_SCALE0 : bit_vector := x"0"; |
PM_DATA1 : bit_vector := x"00"; |
PM_DATA_SCALE1 : bit_vector := x"0"; |
PM_DATA2 : bit_vector := x"00"; |
PM_DATA_SCALE2 : bit_vector := x"0"; |
PM_DATA3 : bit_vector := x"00"; |
PM_DATA_SCALE3 : bit_vector := x"0"; |
PM_DATA4 : bit_vector := x"04"; |
PM_DATA_SCALE4 : bit_vector := x"0"; |
PM_DATA5 : bit_vector := x"00"; |
PM_DATA_SCALE5 : bit_vector := x"0"; |
PM_DATA6 : bit_vector := x"00"; |
PM_DATA_SCALE6 : bit_vector := x"0"; |
PM_DATA7 : bit_vector := x"00"; |
PM_DATA_SCALE7 : bit_vector := x"0"; |
PCIE_GENERIC : bit_vector := "000011101111"; |
GTP_SEL : integer := 0; |
CFG_VEN_ID : std_logic_vector(15 downto 0) := x"10EE"; |
CFG_DEV_ID : std_logic_vector(15 downto 0) := x"BADD"; |
CFG_REV_ID : std_logic_vector(7 downto 0) := x"00"; |
CFG_SUBSYS_VEN_ID : std_logic_vector(15 downto 0) := x"10EE"; |
CFG_SUBSYS_ID : std_logic_vector(15 downto 0) := x"1234"; |
REF_CLK_FREQ : integer := 0 |
); |
port ( |
-- PCI Express Fabric Interface |
pci_exp_txp : out std_logic; |
pci_exp_txn : out std_logic; |
pci_exp_rxp : in std_logic; |
pci_exp_rxn : in std_logic; |
|
-- Transaction (TRN) Interface |
trn_lnk_up_n : out std_logic; |
|
-- Tx |
trn_td : in std_logic_vector(31 downto 0); |
trn_tsof_n : in std_logic; |
trn_teof_n : in std_logic; |
trn_tsrc_rdy_n : in std_logic; |
trn_tdst_rdy_n : out std_logic; |
trn_terr_drop_n : out std_logic; |
trn_tsrc_dsc_n : in std_logic; |
trn_terrfwd_n : in std_logic; |
trn_tbuf_av : out std_logic_vector(5 downto 0); |
trn_tstr_n : in std_logic; |
trn_tcfg_req_n : out std_logic; |
trn_tcfg_gnt_n : in std_logic; |
|
-- Rx |
trn_rd : out std_logic_vector(31 downto 0); |
trn_rsof_n : out std_logic; |
trn_reof_n : out std_logic; |
trn_rsrc_rdy_n : out std_logic; |
trn_rsrc_dsc_n : out std_logic; |
trn_rdst_rdy_n : in std_logic; |
trn_rerrfwd_n : out std_logic; |
trn_rnp_ok_n : in std_logic; |
trn_rbar_hit_n : out std_logic_vector(6 downto 0); |
trn_fc_sel : in std_logic_vector(2 downto 0); |
trn_fc_nph : out std_logic_vector(7 downto 0); |
trn_fc_npd : out std_logic_vector(11 downto 0); |
trn_fc_ph : out std_logic_vector(7 downto 0); |
trn_fc_pd : out std_logic_vector(11 downto 0); |
trn_fc_cplh : out std_logic_vector(7 downto 0); |
trn_fc_cpld : out std_logic_vector(11 downto 0); |
|
-- Host (CFG) Interface |
cfg_do : out std_logic_vector(31 downto 0); |
cfg_rd_wr_done_n : out std_logic; |
cfg_dwaddr : in std_logic_vector(9 downto 0); |
cfg_rd_en_n : in std_logic; |
cfg_err_ur_n : in std_logic; |
cfg_err_cor_n : in std_logic; |
cfg_err_ecrc_n : in std_logic; |
cfg_err_cpl_timeout_n : in std_logic; |
cfg_err_cpl_abort_n : in std_logic; |
cfg_err_posted_n : in std_logic; |
cfg_err_locked_n : in std_logic; |
cfg_err_tlp_cpl_header : in std_logic_vector(47 downto 0); |
cfg_err_cpl_rdy_n : out std_logic; |
cfg_interrupt_n : in std_logic; |
cfg_interrupt_rdy_n : out std_logic; |
cfg_interrupt_assert_n : in std_logic; |
cfg_interrupt_do : out std_logic_vector(7 downto 0); |
cfg_interrupt_di : in std_logic_vector(7 downto 0); |
cfg_interrupt_mmenable : out std_logic_vector(2 downto 0); |
cfg_interrupt_msienable : out std_logic; |
cfg_turnoff_ok_n : in std_logic; |
cfg_to_turnoff_n : out std_logic; |
cfg_pm_wake_n : in std_logic; |
cfg_pcie_link_state_n : out std_logic_vector(2 downto 0); |
cfg_trn_pending_n : in std_logic; |
cfg_dsn : in std_logic_vector(63 downto 0); |
cfg_bus_number : out std_logic_vector(7 downto 0); |
cfg_device_number : out std_logic_vector(4 downto 0); |
cfg_function_number : out std_logic_vector(2 downto 0); |
cfg_status : out std_logic_vector(15 downto 0); |
cfg_command : out std_logic_vector(15 downto 0); |
cfg_dstatus : out std_logic_vector(15 downto 0); |
cfg_dcommand : out std_logic_vector(15 downto 0); |
cfg_lstatus : out std_logic_vector(15 downto 0); |
cfg_lcommand : out std_logic_vector(15 downto 0); |
|
-- System Interface |
sys_clk : in std_logic; |
sys_reset_n : in std_logic; |
trn_clk : out std_logic; |
trn_reset_n : out std_logic; |
received_hot_reset : out std_logic |
); |
end component pcie; |
|
COMPONENT blk_mem_gen_v4_1 |
PORT( |
clka : IN std_logic; |
wea : IN std_logic_vector(0 to 0); |
addra : IN std_logic_vector(8 downto 0); |
dina : IN std_logic_vector(31 downto 0); |
clkb : IN std_logic; |
addrb : IN std_logic_vector(8 downto 0); |
doutb : OUT std_logic_vector(31 downto 0) |
); |
END COMPONENT; |
|
|
|
---- ------- SYNTHESIS ATTRIBUTES: -------------------------------------------------- |
--attribute keep_hierarchy : string; |
--attribute keep_hierarchy of xilinx_pcie2wb: entity is "yes"; |
attribute keep : string; |
attribute keep of cfg_dstatus : signal is "true"; |
attribute keep of tlp_state : signal is "true"; |
|
|
-- --------ARCHITECTURE BODY BEGINS ----------------------------------------------- |
begin |
|
|
cfg_turnoff_ok_n <= '1'; |
|
-- COMPONENT INSTALLATIONS (connecting the IPs to local signals) --------------- |
|
|
-- COMPONENT INSTALLATIONS (connecting the IPs to local signals) --------------- |
|
inst_pcie : pcie |
port map ( |
pci_exp_txp => pci_exp_txp, |
pci_exp_txn => pci_exp_txn, |
pci_exp_rxp => pci_exp_rxp, |
pci_exp_rxn => pci_exp_rxn, |
trn_lnk_up_n => trn_lnk_up_n, |
trn_td => trn_td, -- Bus [31 : 0] |
trn_tsof_n => trn_tsof_n, |
trn_teof_n => trn_teof_n, |
trn_tsrc_rdy_n => trn_tsrc_rdy_n, |
trn_tdst_rdy_n => trn_tdst_rdy_n, |
trn_terr_drop_n => trn_terr_drop_n, |
trn_tsrc_dsc_n => trn_tsrc_dsc_n, |
trn_terrfwd_n => trn_terrfwd_n, |
trn_tbuf_av => trn_tbuf_av, -- Bus [31 : 0] |
trn_tstr_n => trn_tstr_n, |
trn_tcfg_req_n => trn_tcfg_req_n, |
trn_tcfg_gnt_n => trn_tcfg_gnt_n, |
trn_rd => trn_rd, -- Bus [31 : 0] |
trn_rsof_n => trn_rsof_n, |
trn_reof_n => trn_reof_n, |
trn_rsrc_rdy_n => trn_rsrc_rdy_n, |
trn_rsrc_dsc_n => trn_rsrc_dsc_n, |
trn_rdst_rdy_n => trn_rdst_rdy_n, |
trn_rerrfwd_n => trn_rerrfwd_n, |
trn_rnp_ok_n => trn_rnp_ok_n, |
trn_rbar_hit_n => trn_rbar_hit_n, -- Bus [31 : 0] |
trn_fc_sel => trn_fc_sel, -- Bus [31 : 0] |
trn_fc_nph => trn_fc_nph, -- Bus [31 : 0] |
trn_fc_npd => trn_fc_npd, -- Bus [31 : 0] |
trn_fc_ph => trn_fc_ph, -- Bus [31 : 0] |
trn_fc_pd => trn_fc_pd, -- Bus [31 : 0] |
trn_fc_cplh => trn_fc_cplh, -- Bus [31 : 0] |
trn_fc_cpld => trn_fc_cpld, -- Bus [31 : 0] |
cfg_do => cfg_do, -- Bus [31 : 0] |
cfg_rd_wr_done_n => cfg_rd_wr_done_n, |
cfg_dwaddr => cfg_dwaddr, -- Bus [31 : 0] |
cfg_rd_en_n => cfg_rd_en_n, |
cfg_err_ur_n => cfg_err_ur_n, |
cfg_err_cor_n => cfg_err_cor_n, |
cfg_err_ecrc_n => cfg_err_ecrc_n, |
cfg_err_cpl_timeout_n => cfg_err_cpl_timeout_n, |
cfg_err_cpl_abort_n => cfg_err_cpl_abort_n, |
cfg_err_posted_n => cfg_err_posted_n, |
cfg_err_locked_n => cfg_err_locked_n, |
cfg_err_tlp_cpl_header => cfg_err_tlp_cpl_header, -- Bus [31 : 0] |
cfg_err_cpl_rdy_n => cfg_err_cpl_rdy_n, |
cfg_interrupt_n => cfg_interrupt_n, |
cfg_interrupt_rdy_n => cfg_interrupt_rdy_n, |
cfg_interrupt_assert_n => cfg_interrupt_assert_n, |
cfg_interrupt_do => cfg_interrupt_do, -- Bus [31 : 0] |
cfg_interrupt_di => cfg_interrupt_di, -- Bus [31 : 0] |
cfg_interrupt_mmenable => cfg_interrupt_mmenable, -- Bus [31 : 0] |
cfg_interrupt_msienable => cfg_interrupt_msienable, |
cfg_turnoff_ok_n => cfg_turnoff_ok_n, |
cfg_to_turnoff_n => cfg_to_turnoff_n, |
cfg_pm_wake_n => cfg_pm_wake_n, |
cfg_pcie_link_state_n => cfg_pcie_link_state_n, -- Bus [31 : 0] |
cfg_trn_pending_n => cfg_trn_pending_n, |
cfg_dsn => cfg_dsn, -- Bus [31 : 0] |
cfg_bus_number => cfg_bus_number, -- Bus [31 : 0] |
cfg_device_number => cfg_device_number, -- Bus [31 : 0] |
cfg_function_number => cfg_function_number, -- Bus [31 : 0] |
cfg_status => cfg_status, -- Bus [31 : 0] |
cfg_command => cfg_command, -- Bus [31 : 0] |
cfg_dstatus => cfg_dstatus, -- Bus [31 : 0] |
cfg_dcommand => cfg_dcommand, -- Bus [31 : 0] |
cfg_lstatus => cfg_lstatus, -- Bus [31 : 0] |
cfg_lcommand => cfg_lcommand, -- Bus [31 : 0] |
sys_clk => sys_clk, |
sys_reset_n => sys_reset_n, |
trn_clk => trn_clk, |
trn_reset_n => trn_reset_n, |
received_hot_reset => received_hot_reset |
); |
|
--block ram for RX TLP: |
Inst_bram_rxtlp: blk_mem_gen_v4_1 PORT MAP( |
clka => trn_clk, |
wea => bram_rxtlp_we, |
addra => bram_rxtlp_writeaddress(8 downto 0), |
dina => bram_rxtlp_writedata, |
clkb => trn_clk, |
addrb => bram_rxtlp_readaddress(8 downto 0), |
doutb => bram_rxtlp_readdata |
); |
|
--block ram for TX TLP: |
Inst_bram_txtlp: blk_mem_gen_v4_1 PORT MAP( |
clka => trn_clk, |
wea => bram_txtlp_we, |
addra => bram_txtlp_writeaddress(8 downto 0), |
dina => bram_txtlp_writedata, |
clkb => trn_clk, |
addrb => bram_txtlp_readaddress(8 downto 0), |
doutb => bram_txtlp_readdata |
); |
|
|
|
|
|
-- MAIN LOGIC: --------------------------------------------------------------------------------------------- |
|
|
|
--System Signals:-------------------------------- |
|
--Clock Input Buffer for differential system clock |
IBUFDS_inst : IBUFDS |
generic map ( |
DIFF_TERM => TRUE, -- Differential Termination |
IBUF_LOW_PWR => FALSE, -- Low power (TRUE) vs. performance (FALSE) setting for referenced I/O standards |
IOSTANDARD => "DEFAULT") |
port map ( |
O => sys_clk, -- Buffer output |
I => sys_clk_p, -- Diff_p buffer input (connect directly to top-level port) |
IB => sys_clk_n -- Diff_n buffer input (connect directly to top-level port) |
); |
|
--wishbone clock output: |
pcie_bar0_wb_clk_o <= trn_clk; |
--pcie_bar1_wb_clk_o <= trn_clk; |
|
|
--use one of these for resetting logic in this file: |
pciewb_localreset_n <= sys_reset_n; --dont wait for the PCIE-EP to finish its init. |
--pciewb_localreset_n <= trn_reset_n; |
--pciewb_localreset_n <= trn_reset_n and (not trn_lnk_up_n) and (not received_hot_reset); |
--reset to the core: |
--sys_reset_n comes from toplevel directly to the core. same name |
--reset output to other cores: |
pcie_resetout <= not pciewb_localreset_n; |
|
--trn_lnk_up_n --not used. |
|
|
--pcie ep ip config port: ---------------------------------------------------------- |
|
--trn_fc_sel <= "000"; |
|
trn_rnp_ok_n <= '0'; |
--trn_terrfwd_n <= '1'; |
|
--trn_tcfg_gnt_n <= '0'; |
|
cfg_err_cor_n <= '1'; |
cfg_err_ur_n <= '1'; |
cfg_err_ecrc_n <= '1'; |
cfg_err_cpl_timeout_n <= '1'; |
cfg_err_cpl_abort_n <= '1'; |
cfg_err_posted_n <= '0'; |
cfg_err_locked_n <= '1'; |
cfg_pm_wake_n <= '1'; |
cfg_trn_pending_n <= '1'; |
|
--trn_tstr_n <= '0'; |
--cfg_interrupt_assert_n <= '1'; --used in a process at the bottom of this file |
--cfg_interrupt_n <= '1'; |
--cfg_interrupt_di <= x"00"; --intA used |
|
cfg_err_tlp_cpl_header <= (OTHERS => '0'); |
cfg_dwaddr <= (OTHERS => '0'); |
cfg_rd_en_n <= '1'; |
--serial number: |
cfg_dsn <= (OTHERS => '0'); |
|
-- AT THE BOTTOM OF THIS FILE: |
-- --some fix values: |
-- trn_tsrc_dsc_n <= '1'; --no errors on trn bus |
-- trn_tstr_n <= '0'; --pipelining (0= link may begin before the entire packet has been written) |
-- trn_tcfg_gnt_n <= '0'; --no tlp priorities |
-- trn_terrfwd_n <= '1'; --no errors on trn |
-- --nc: trn_tbuf_av, trn_terr_drop_n, trn_tcfg_req_n |
|
|
|
--use this in read completion packets: |
cfg_completer_id <= cfg_bus_number & cfg_device_number & cfg_function_number; |
|
|
|
|
|
|
-- WISBONE BACK-end INTERFACE ---------------------------------------------------- |
|
--main state machine: set states, capture inputs, set addr/data outputs |
--minimum 2 clock cycles / transaction. writes are posted, reads have wait states. |
process (pciewb_localreset_n, trn_clk, wb0_state, start_read_wb0, start_write_wb0, |
pcie_bar0_wb_addr_o_feed, pcie_bar0_wb_data_o_feed, pcie_bar0_wb_sel_o_feed) |
begin |
if (pciewb_localreset_n='0') then |
wb0_state <= "00000000"; |
wb_transaction_complete <= '0'; |
pcie_bar0_wb_addr_o <= "0000000000000000000000000000"; |
pcie_bar0_wb_sel_o <= "0000"; |
pcie_bar0_wb_data_o <= "00000000000000000000000000000000"; |
wb_transaction_complete <='0'; |
else |
if (trn_clk'event and trn_clk = '1') then |
case ( wb0_state ) is |
|
--********** IDLE STATE ********** |
when "00000000" => --state 0 |
wb_transaction_complete <='0'; |
pcie_bar0_wb_sel_o <= pcie_bar0_wb_sel_o_feed; |
pcie_bar0_wb_addr_o <= pcie_bar0_wb_addr_o_feed; |
if (start_read_wb0 ='1') then --go to read |
wb0_state <= "00000001"; |
elsif (start_write_wb0 ='1') then --go to write |
wb0_state <= "00000010"; |
--no endian swap: pcie_bar0_wb_data_o <= pcie_bar0_wb_data_o_feed; |
pcie_bar0_wb_data_o (7 downto 0) <= pcie_bar0_wb_data_o_feed(31 downto 24); --swap endianism |
pcie_bar0_wb_data_o (15 downto 8) <= pcie_bar0_wb_data_o_feed(23 downto 16); --swap endianism |
pcie_bar0_wb_data_o (23 downto 16) <= pcie_bar0_wb_data_o_feed(15 downto 8); --swap endianism |
pcie_bar0_wb_data_o (31 downto 24) <= pcie_bar0_wb_data_o_feed(7 downto 0); --swap endianism |
end if; |
|
--********** READ STATE ********** |
--set the outputs, |
--if ACK asserted, sample the data input |
--The hold requirements are oversatisfyed by going back to idle, and by the fact that the slave uses the cyc/stb/wr strobes synchronously. |
when "00000001" => --state 1 |
if (pcie_bar0_wb_ack_i='1') then |
--no endian swap: pcie_bar0_wb_data_i_latched <= pcie_bar0_wb_data_i; --sample the incoming data |
pcie_bar0_wb_data_i_latched (7 downto 0) <= pcie_bar0_wb_data_i(31 downto 24); --swap endianism |
pcie_bar0_wb_data_i_latched (15 downto 8) <= pcie_bar0_wb_data_i(23 downto 16); --swap endianism |
pcie_bar0_wb_data_i_latched (23 downto 16) <= pcie_bar0_wb_data_i(15 downto 8); --swap endianism |
pcie_bar0_wb_data_i_latched (31 downto 24) <= pcie_bar0_wb_data_i(7 downto 0); --swap endianism |
wb_transaction_complete <='1'; --signalling ready, but only for one clock cycle |
wb0_state <= "00000000"; --go to state 0 |
else |
wb_transaction_complete <='0'; |
end if; |
|
--********** WRITE STATE ********** |
--if ACK asserted, go back to idle |
--The hold requirements are oversatisfyed by waiting for ACK to remove write data |
when "00000010" => --state 2 |
if (pcie_bar0_wb_ack_i='1') then |
wb0_state <= "00000000"; --go to state 0 |
wb_transaction_complete <='1'; |
else |
wb_transaction_complete <='0'; |
end if; |
|
when others => --error |
wb0_state <= "00000000"; --go to state 0 |
end case; |
end if; |
end if; |
end process; |
--sync control on wb-control signals: |
process (pciewb_localreset_n, wb0_state) |
begin |
if (pciewb_localreset_n='0') then |
pcie_bar0_wb_cyc_o <= '0'; |
pcie_bar0_wb_stb_o <= '0'; |
pcie_bar0_wb_wr_o <= '0'; |
else |
if (wb0_state = "00000000") then --idle |
pcie_bar0_wb_cyc_o <= '0'; |
pcie_bar0_wb_stb_o <= '0'; |
pcie_bar0_wb_wr_o <= '0'; |
elsif (wb0_state = "00000001") then --read |
pcie_bar0_wb_cyc_o <= '1'; |
pcie_bar0_wb_stb_o <= '1'; |
pcie_bar0_wb_wr_o <= '0'; |
elsif (wb0_state = "00000010") then --write |
pcie_bar0_wb_cyc_o <= '1'; |
pcie_bar0_wb_stb_o <= '1'; |
pcie_bar0_wb_wr_o <= '1'; |
else |
pcie_bar0_wb_cyc_o <= '0'; |
pcie_bar0_wb_stb_o <= '0'; |
pcie_bar0_wb_wr_o <= '0'; |
end if; |
end if; |
end process; |
|
|
|
|
|
|
|
|
-- INTERFACE TO THE PCIE-EP IP -------------------------------------------------------- |
--trn_clk and trn_reset_n are the same as the pcie_resetout and pcie_bar0_wb_clk_o, |
--so it is not a clock domain crossing. |
|
|
-- TX: INTERFACE TO THE PCIE-EP: TRANSMIT TLP PACKETS:----- |
--Read completion is 3DW header. This core only transmits read completion or Unbsupported request packets. |
process (pciewb_localreset_n, trn_clk, epif_tx_state, bram_txtlp_readdata , bram_txtlp_readaddress, |
pcie_there_is_a_new_tlp_to_transmit, tlp_payloadsize_dwords, txtrn_counter) |
begin |
if (pciewb_localreset_n='0') then |
epif_tx_state <= "00000000"; |
trn_tsrc_rdy_n_1 <='1'; |
trn_tsof_n1 <= '1'; |
trn_teof_n <= '1'; |
trn_td <= (OTHERS => '0'); |
pcie_tlp_tx_complete <= '0'; |
txtrn_counter <= "00000001"; |
bram_txtlp_readaddress <= (OTHERS => '0'); |
else |
if (trn_clk'event and trn_clk = '1') then |
case ( epif_tx_state ) is |
|
--********** idle STATE ********** |
when "00000000" => --state 0 |
--if there is a new TLP assembled and the EP is ready, |
--start the tx-trn bus transaction. |
if (pcie_there_is_a_new_tlp_to_transmit='1') then |
epif_tx_state <= "00000001"; --next state |
end if; |
trn_tsrc_rdy_n_1 <='1'; |
trn_tsof_n1 <= '1'; |
trn_teof_n <= '1'; |
trn_td <= (OTHERS => '0'); |
pcie_tlp_tx_complete <= '0'; |
txtrn_counter <= "00000001"; |
bram_txtlp_readaddress <= (OTHERS => '0'); |
|
--********** ready-wait STATE ********** |
when "00000001" => --state 1 |
--if there is a new TLP assembled and the EP is ready, |
--start the tx-trn bus transaction. |
if (trn_tdst_rdy_n='0') then |
epif_tx_state <= "00000010"; --next state |
end if; |
trn_tsrc_rdy_n_1 <='1'; |
trn_tsof_n1 <= '1'; |
trn_teof_n <= '1'; |
trn_td <= (OTHERS => '0'); |
pcie_tlp_tx_complete <= '0'; |
txtrn_counter <= "00000001"; |
bram_txtlp_readaddress <= (OTHERS => '0'); |
|
--********** transfer STATE ********** |
when "00000010" => --state 2 |
trn_tsrc_rdy_n_1 <='0'; |
trn_td <= bram_txtlp_readdata; |
if (trn_tdst_rdy_n='0') then |
txtrn_counter <= txtrn_counter +1; |
bram_txtlp_readaddress <= bram_txtlp_readaddress +1; |
end if; |
if (txtrn_counter = "00000010") then |
trn_tsof_n1 <= '0'; --start |
else |
trn_tsof_n1 <= '1'; |
end if; |
--test number of dwords: |
if (txtrn_counter = tlp_payloadsize_dwords +4) then -- "+3" is the header and "+1" is for the delay |
--this is the last dword, next clk is next state |
epif_tx_state <= "00000000"; --back to idle, since finished |
trn_teof_n <= '0'; --end |
pcie_tlp_tx_complete <= '1'; --assert for 1 clk |
else |
trn_teof_n <= '1'; --not end yet |
pcie_tlp_tx_complete <= '0'; --not complete yet |
end if; |
|
when others => --error |
epif_tx_state <= "00000000"; --back to idle |
trn_tsrc_rdy_n_1 <='1'; |
trn_tsof_n1 <= '1'; |
trn_teof_n <= '1'; |
trn_td <= (OTHERS => '0'); |
pcie_tlp_tx_complete <= '0'; |
txtrn_counter <= "00000001"; |
|
end case; |
end if; |
end if; |
end process; |
|
--this (little delay) is to fix a hold time violation created inside the pcie-ep ip: |
trn_tsrc_rdy_n <= trn_tsrc_rdy_n_1 or (not pciewb_localreset_n); |
trn_tsof_n <= trn_tsof_n1 or (not pciewb_localreset_n); |
|
|
|
--some fix values: |
trn_tsrc_dsc_n <= '1'; --no errors on trn bus |
trn_tstr_n <= '0'; --pipelining |
trn_tcfg_gnt_n <= '0'; --no tlp priorities |
trn_terrfwd_n <= '1'; --no errors on trn |
--nc: trn_tbuf_av, trn_terr_drop_n, trn_tcfg_req_n |
|
|
|
|
|
-- RX: INTERFACE TO THE PCIE-EP: GET thereceived TLP PACKETS:- ---- |
process (pciewb_localreset_n, trn_clk, epif_rx_state, tlp_state, trn_rx_counter, |
bram_rxtlp_writeaddress, rxstm_readytoroll, trn_rsof_n, tlpstm_isin_idle, trn_rdst_rdy_n) |
begin |
if (pciewb_localreset_n='0') then |
pcie_just_received_a_new_tlp <= '0'; |
epif_rx_state <= "00000000"; |
trn_rdst_rdy_n <= '1'; |
trn_rx_counter <= (OTHERS => '0'); |
bram_rxtlp_we <= "0"; |
bram_rxtlp_writeaddress <= (OTHERS => '0'); |
bram_rxtlp_writedata <= (OTHERS => '0'); |
rxstm_readytoroll <= '0'; |
else |
if (trn_clk'event and trn_clk = '1') then |
|
case ( epif_rx_state ) is |
|
--********** idle STATE ********** |
when "00000000" => --state 0 |
pcie_just_received_a_new_tlp <= '0'; |
bram_rxtlp_writedata <= trn_rd; |
if (trn_rsrc_rdy_n='0' and trn_rsof_n='0' and tlpstm_isin_idle = '1' and trn_rdst_rdy_n='0') then |
trn_rx_counter <= trn_rx_counter +1; |
bram_rxtlp_writeaddress <= bram_rxtlp_writeaddress +1; |
epif_rx_state <= "00000001"; |
else |
trn_rx_counter <= (OTHERS => '0'); |
bram_rxtlp_writeaddress <= (OTHERS => '0'); |
end if; |
--destination ready: |
if (tlpstm_isin_idle = '1')then |
trn_rdst_rdy_n <= '0'; |
else |
trn_rdst_rdy_n <= '1'; |
end if; |
--write into buffer: |
if (trn_rsrc_rdy_n='0' and trn_rsof_n='0' and tlpstm_isin_idle = '1') then |
bram_rxtlp_we <= "1"; |
rxstm_readytoroll <= '1'; |
else |
bram_rxtlp_we <= "0"; |
rxstm_readytoroll <= '0'; |
end if; |
|
--********** read STATE ********** |
when "00000001" => --state 1 |
rxstm_readytoroll <= '0'; |
if (trn_reof_n ='0') then --last dw |
epif_rx_state <= "00000010"; --for the next clk cycle |
trn_rdst_rdy_n <= '1'; --ok, dont send more yet |
end if; |
if (trn_rsrc_rdy_n='0') then --only act if the EP was ready |
trn_rx_counter <= trn_rx_counter +1; |
bram_rxtlp_writeaddress <= bram_rxtlp_writeaddress +1; |
bram_rxtlp_writedata <= trn_rd; |
end if; |
--in an early stage of this transfer, the scheduler can already |
--start working on the data, this way its pipelined, so the latency is lower. |
if (trn_rx_counter = "00000010") then |
pcie_just_received_a_new_tlp <= '1';--assert for one clk only |
else |
pcie_just_received_a_new_tlp <= '0'; |
end if; |
|
--********** finished filling up RX TLP STATE ********** |
when "00000010" => --state 2 |
epif_rx_state <= "00000000"; |
trn_rx_counter <= (OTHERS => '0'); |
|
when others => --error |
epif_rx_state <= "00000000"; --go to state 0 |
end case; |
end if; |
end if; |
end process; |
|
--fixed connections: |
--trn_rnp_ok_ntrn_rnp_ok_n <= '0'; --ready to receive non-posted |
--not connected: trn_rerrfwd_n, trn_rsrc_dsc_n, trn_rbar_hit_n |
|
|
|
|
|
-- flow control: INTERFACE TO THE PCIE-EP: - ---- |
--not used. pcie-ep provides information about credit status. |
--unconnected: trn_fc_nph, trn_fc_npd, trn_fc_ph, trn_fc_pd, trn_fc_cplh, trn_fc_cpld |
trn_fc_sel <= "000"; |
|
|
|
|
|
-- --- GLUE LOGIC BETWEEN THE PCIE CORE-IF AND THE WB INTERFACES ----------------------- |
-- --- ALSO TLP PACKET PROCESSING. |
--Theory of operation: |
--RX: If we receive a TLP (pcie_just_received_a_new_tlp goes high for one clock cycle), |
--then store it (pcie_received_tlp), decode it (to figure out if its read request, |
--posted write or non-supported request), then assert a flag (start_write_wb0 or |
--start_read_wb0)to initiate a wishbone cycle. |
--TX: At the completion of a wishbone read, the wishbone statemachine asserts the |
--wb_transaction_complete flag, so we can assemble the TX TLP packet (pcie_to_transmit_tlp) |
--and assert the flag named pcie_there_is_a_new_tlp_to_transmit. This packet will be |
--a read completion packet on the PCIe link. |
-- |
--This core can handle 1...8 DWORD accesses in one request (max 256bit payload ), |
--and can handle only one request at a time. If a new request is arriving while |
--processing the previous one (e.g. getting the data from a wishbone read), then |
--the state machine will not process it immediately, or it will hang. So the user |
--software has to wait for the previous read completion before issueing a new request. |
--The multiple DWORDs are handled separately by the WB statemachine. |
--Performance: WishBone bus: 62.5MHz, 32bit, 3clk/access -> 83MBytes/sec |
-- |
--TLP decoding: |
--Header+Payload_data+TLP_DIGEST(ECRC). |
--received Header: |
--First Dword: bit.30/29=format: 00=3DW-header+no_data, 01=4DW-header+no_data, |
--10=3DW-header+data, 11=4DW-header+data. bit.28:24=type: 00000 or 00001 are memory |
--read requests, 00000 or 00001 are memory write request if type=1x. read request |
--completion is 01010 and type=10. bit.9:0 is payload size [DW]. |
--Second Dword: bit.31:16 is requester ID. bit3:0 is first dword byte enable, bit.7:4 is |
--byte enable for last dword data. intermediate dwords have all bytes enabled. |
--Third DWORD: address, where bit.1:0=00b. 4DW headers are for 64bit. 64bit adressing |
--uses 3rd-dword for addre63:32, 4th dword for addr31:0. |
-- |
--The TLP variables in this core: BRAM memory used store TLP, up to 1-2kBytes |
-- |
--Read completion is 3DW header and routed by completer-ID and requester-ID, not address. |
--The core has to store the requester ID and feed it back in the completion packet. |
--Completion status: 000=successful, 100=completer_abort, 001=unsupported request. byte |
--count is N.of bytes left. lower_address is the first enabled byte of data returned |
--with the Completion. |
-- |
-- Completion packet header: |
--DW1 > |
--7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 |
--r FMT type----- r TC--- reserv- T E att r r lenght------------- |
-- x 0 D P rib |
--DW2 > |
--7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 |
--COMPLETER_ID------------------- statu B byte_count------------- |
-- CM |
--DW3 > |
--7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 |
--REQUESTER_ID------------------- tag------------ r lower_address |
|
|
--TLP-protocol statemachine: |
process (pciewb_localreset_n, trn_clk, tlp_state, |
pcie_just_received_a_new_tlp, tlp_datacount, |
bram_rxtlp_readdata, bram_txtlp_writeaddress, bram_rxtlp_readaddress, |
tlp_state_copy, rxtlp_decodedaddress, |
rxtlp_header_dw1, rxtlp_header_dw2, rxtlp_header_dw3, rxtlp_header_dw4, |
bit10, rxtlp_firstdw_be, wb_transaction_complete, flag1, rxdw1_23_0, pcie_rxtlp_tag, |
tlp_payloadsize_dwords, pcie_bar0_wb_data_i_latched, cfg_completer_id, |
rxtlp_requesterid) |
begin |
if (pciewb_localreset_n='0') then |
start_read_wb0 <= '0'; |
start_write_wb0 <= '0'; |
pcie_bar0_wb_data_o_feed <= (others => '0'); |
pcie_bar0_wb_addr_o_feed <= (others => '0'); |
pcie_bar0_wb_sel_o_feed <= (others => '0'); |
pcie_there_is_a_new_tlp_to_transmit <= '0'; |
rxtlp_decodedaddress<= (others => '0'); |
tlp_payloadsize_dwords <= (others => '0'); |
rxtlp_firstdw_be <= (others => '0'); |
rxtlp_lastdw_be <= (others => '0'); |
rxtlp_requesterid <= (others => '0'); |
tlp_state <= (others => '0'); |
tlp_state_copy <= (others => '0'); |
bram_txtlp_we <= "0"; |
bram_txtlp_writeaddress <= (others => '0'); |
bram_txtlp_writedata <= (others => '0'); |
bram_rxtlp_readaddress <= (others => '0'); |
rxtlp_header_dw1 <= "01111111000000000000000000000000"; |
rxtlp_header_dw2 <= (others => '0'); |
rxtlp_header_dw3 <= (others => '0'); |
rxtlp_header_dw4 <= (others => '0'); |
flag1 <= '0'; |
rxdw1_23_0 <= (others => '0'); |
pcie_rxtlp_tag <= (others => '0'); |
rcompl_bytecount_field <= (others => '0'); |
tlpstm_isin_idle <= '1'; |
else |
if (trn_clk'event and trn_clk = '1') then |
case ( tlp_state ) is |
|
--********** IDLE STATE ********** |
--also re-initialize signals... |
when "00000000" => --state 0 |
if (pcie_just_received_a_new_tlp='1') then |
tlp_state <= "00000001"; --to tlp decoding state |
tlpstm_isin_idle <= '0'; |
else |
tlpstm_isin_idle <= '1'; |
end if; |
start_write_wb0 <= '0'; |
start_read_wb0 <= '0'; |
tlp_state_copy <= tlp_state; |
bram_txtlp_we <= "0"; |
bram_txtlp_writeaddress <= (others => '0'); |
bram_txtlp_writedata <= (others => '0'); |
bram_rxtlp_readaddress <= (others => '0'); |
tlp_datacount <= "00000001"; |
rxtlp_header_dw1 <= "01111111000000000000000000000000"; --this is to prevent false decode |
pcie_bar0_wb_data_o_feed <= (others => '0'); |
pcie_bar0_wb_addr_o_feed <= (others => '0'); |
pcie_bar0_wb_sel_o_feed <= (others => '0'); |
rxtlp_header_dw2 <= (others => '0'); |
rxtlp_header_dw3 <= (others => '0'); |
rxtlp_header_dw4 <= (others => '0'); |
rxdw1_23_0 <= (others => '0'); |
pcie_rxtlp_tag <= (others => '0'); |
pcie_there_is_a_new_tlp_to_transmit <= '0'; |
rxtlp_decodedaddress<= (others => '0'); |
tlp_payloadsize_dwords <= (others => '0'); |
rxtlp_firstdw_be <= (others => '0'); |
rxtlp_lastdw_be <= (others => '0'); |
rxtlp_requesterid <= (others => '0'); |
rcompl_bytecount_field <= (others => '0'); |
|
|
--********** TLP ARRIVED STATE ********** |
--read TLP out of EP, decode and decide, |
--latch address/sel/wr_data |
--All the "IF"-statements use address+1, because the BRAM read side has data available 1clk late!!! |
--Added an ectra clock delay, based on testing, since the data is one more CLK late. |
when "00000001" => --state 1 |
--latch the header: |
bram_rxtlp_readaddress <= bram_rxtlp_readaddress +1; |
if (bram_rxtlp_readaddress = "000000010") then |
rxtlp_header_dw1 <= bram_rxtlp_readdata; |
elsif (bram_rxtlp_readaddress = "000000011") then |
rxtlp_header_dw2 <= bram_rxtlp_readdata; |
elsif (bram_rxtlp_readaddress = "000000100") then |
rxtlp_header_dw3 <= bram_rxtlp_readdata; |
elsif (bram_rxtlp_readaddress = "000000101") then |
rxtlp_header_dw4 <= bram_rxtlp_readdata; |
end if; |
--decode some parameters: |
tlp_payloadsize_dwords <= rxtlp_header_dw1(7 downto 0); |
rxtlp_firstdw_be <= rxtlp_header_dw2(3 downto 0); |
rxtlp_lastdw_be <= rxtlp_header_dw2(7 downto 4); |
rxtlp_requesterid <= rxtlp_header_dw2(31 downto 16); |
flag1 <= rxtlp_header_dw1(31); |
rxdw1_23_0 <= rxtlp_header_dw1(23 downto 0); --various fields pcie_received_tlp (22 downto 0); |
pcie_rxtlp_tag <= rxtlp_header_dw2(15 downto 8) ; --pcie_received_tlp (47 downto 40);--tag |
--decide based on header: |
if (rxtlp_header_dw1(30 downto 24)="0000000") then --32bit read |
if (bram_rxtlp_readaddress = "000000100") then |
rxtlp_decodedaddress <= bram_rxtlp_readdata; |
bram_txtlp_writeaddress(8 downto 0) <= "000000011"; --point after the 3dw readcompl header |
tlp_state <= "00000011"; |
end if; |
elsif (rxtlp_header_dw1(30 downto 24)="0100000") then --64bit read |
if (bram_rxtlp_readaddress = "000000101") then |
rxtlp_decodedaddress <= bram_rxtlp_readdata; |
bram_txtlp_writeaddress(8 downto 0) <= "000000011"; --point after the 3dw readcompl header |
tlp_state <= "00000011"; |
end if; |
elsif (rxtlp_header_dw1(30 downto 24)="1000000") then --32bit write |
if (bram_rxtlp_readaddress = "000000100") then |
rxtlp_decodedaddress <= bram_rxtlp_readdata; |
tlp_state <= "00000010"; |
end if; |
elsif (rxtlp_header_dw1(30 downto 24)="1100000") then --64bit write |
if (bram_rxtlp_readaddress = "000000101") then |
rxtlp_decodedaddress <= bram_rxtlp_readdata; |
tlp_state <= "00000010"; |
end if; |
elsif (rxtlp_header_dw1(30 downto 24)="1111111") then --just wait until this gets a real value |
rxtlp_decodedaddress <= bram_rxtlp_readdata; |
else --unsupported request |
if (bram_rxtlp_readaddress = "000000100") then |
tlp_state <= "00000101"; |
bram_txtlp_writeaddress <= "111111111"; |
end if; |
end if; |
|
|
--********** WRITE STATE ********** |
--initiate WB write(s) (1...N DWORD accesses) |
when "00000010" => --state 2 |
pcie_bar0_wb_addr_o_feed(27 downto 2) <= rxtlp_decodedaddress(27 downto 2) + tlp_datacount -1; --256MBytes size is hardcoded here, by cutting 4-MSB off |
pcie_bar0_wb_addr_o_feed(1 downto 0) <= bit10(1 downto 0); |
pcie_bar0_wb_sel_o_feed <= rxtlp_firstdw_be; |
pcie_bar0_wb_data_o_feed <= bram_rxtlp_readdata; |
tlp_state_copy <= tlp_state; |
if (tlp_state_copy = tlp_state) then |
start_write_wb0 <= '0'; |
else --generate just one pulse, at the first clk cycle in this state |
start_write_wb0 <= '1'; |
end if; |
if (wb_transaction_complete='1') then --one DW transfer completed |
|
if (tlp_payloadsize_dwords = tlp_datacount) then --all data completed |
tlp_state <= "00000000"; --to idle |
else |
tlp_state <= "00010100"; --restart wb transaction with new data |
bram_rxtlp_readaddress <= bram_rxtlp_readaddress +1; |
tlp_datacount <= tlp_datacount +1; |
end if; |
end if; |
--* Write restart state * |
when "00010100" => --state 20 |
tlp_state <= "00000010"; |
|
|
--********** READ STATE ********** |
--initiate WB read, then go to completion state |
when "00000011" => --state 3 |
pcie_bar0_wb_addr_o_feed(27 downto 2) <= rxtlp_decodedaddress(27 downto 2) + tlp_datacount -1; |
pcie_bar0_wb_addr_o_feed(1 downto 0) <= bit10(1 downto 0); |
pcie_bar0_wb_sel_o_feed <= rxtlp_firstdw_be; |
tlp_state_copy <= tlp_state; |
if (tlp_state_copy = tlp_state) then |
start_read_wb0 <= '0'; |
else --generate just one pulse |
start_read_wb0 <= '1'; |
end if; |
if (wb_transaction_complete='1') then |
bram_txtlp_writedata <= pcie_bar0_wb_data_i_latched; |
bram_txtlp_we <= "1"; |
if (tlp_payloadsize_dwords = tlp_datacount)then |
tlp_state <= "01111110"; --read completion |
--bram_txtlp_writeaddress remains the same to capture data in next clock cycle |
else |
tlp_state <= "00011110"; --one more wb read |
bram_txtlp_writeaddress <= bram_txtlp_writeaddress +1; |
tlp_datacount <= tlp_datacount +1; |
end if; |
else |
bram_txtlp_we <= "0"; |
end if; |
--* read restart STATE * |
when "00011110" => --state 30 |
tlp_state <= "00000011"; |
bram_txtlp_we <= "0"; |
--intermediate state before completion (to ensure data latch at address-4) |
when "01111110" => --state 126 |
tlp_state <= "00000100"; |
bram_txtlp_writeaddress <= (OTHERS => '0'); |
--pre-write header-DW1: |
bram_txtlp_writedata (31) <= flag1; --reserved |
bram_txtlp_writedata (30 downto 24) <= "1001010"; --type= rd completion |
bram_txtlp_writedata (23 downto 0) <= rxdw1_23_0; --various fields pcie_received_tlp (23 downto 0); |
--Calculate completion header's "rcompl_bytecount_field" from rxtlp_firstdw_be, rxtlp_lastdw_be, tlp_payloadsize_dwords |
if (rxtlp_lastdw_be="0000") then --max 1DW |
if (rxtlp_firstdw_be="1111") then --4bytes |
rcompl_bytecount_field <= "0000000100"; |
elsif (rxtlp_firstdw_be="0111" or rxtlp_firstdw_be="1110") then |
rcompl_bytecount_field <= "0000000011"; |
elsif (rxtlp_firstdw_be="0011" or rxtlp_firstdw_be="1100" or rxtlp_firstdw_be="0110") then |
rcompl_bytecount_field <= "0000000010"; |
else |
rcompl_bytecount_field <= "0000000001"; |
end if; |
else --more than 1DW: right now we dont support non-aligned multi-Dword accesses |
rcompl_bytecount_field(9 downto 2) <= tlp_payloadsize_dwords; |
rcompl_bytecount_field(1 downto 0) <= "00"; |
end if; |
|
|
--********** READ COMPLETION STATE ********** |
--assemble the tx TLP and initiate the transmit |
--buffer signals bram_txtlp_we, bram_txtlp_writeaddress, bram_txtlp_writedata |
when "00000100" => --state 4 |
tlp_state_copy <= tlp_state; |
bram_txtlp_writeaddress <= bram_txtlp_writeaddress +1; |
if (bram_txtlp_writeaddress="000000000") then --if address is 0: launch data for next lock/address(1): header-2.dw |
bram_txtlp_writedata (31 downto 16) <= cfg_completer_id; --completer ID |
bram_txtlp_writedata (15 downto 13) <= "000"; --status= succesful*** |
bram_txtlp_writedata (12) <= '0'; --reserved |
bram_txtlp_writedata (11 downto 10) <= "00"; |
bram_txtlp_writedata (9 downto 0) <= rcompl_bytecount_field; --total bytes returned |
bram_txtlp_we <= "1"; |
elsif (bram_txtlp_writeaddress="000000001") then --if address is 1: launch data for next lock/address(2): header-3.dw |
bram_txtlp_writedata (31 downto 16) <= rxtlp_requesterid; --requester ID |
bram_txtlp_writedata (15 downto 8) <= pcie_rxtlp_tag ; --pcie_received_tlp (47 downto 40);--tag |
bram_txtlp_writedata (7) <= '0'; --reserved |
bram_txtlp_writedata (6 downto 2) <= rxtlp_decodedaddress(6 downto 2); --lower address |
bram_txtlp_writedata (1 downto 0) <= bit10(1 downto 0); --lower address |
else --data dwords, disable writes from next clock cycle |
bram_txtlp_we <= "0"; |
end if; |
--one pulse to start the ep-if statemachine, upon arriving to this state |
if (tlp_state_copy = tlp_state) then |
pcie_there_is_a_new_tlp_to_transmit <= '0'; |
else |
pcie_there_is_a_new_tlp_to_transmit <= '1'; |
end if; |
--back to idle when the ep-if tx is finished: (wait to avoid overwrite) |
if (pcie_tlp_tx_complete='1') then |
tlp_state <= "00000000"; |
end if; |
|
|
--********** UNSUPPORTED REQUEST STATE ********** |
--completion response with status=001 |
when "00000101" => --state 5 |
tlp_state_copy <= tlp_state; |
tlp_payloadsize_dwords <= "00000000"; |
bram_txtlp_writeaddress <= bram_txtlp_writeaddress +1; |
--assembling the TLP packet: ) |
if (bram_txtlp_writeaddress="111111111") then --header 1.dw |
bram_txtlp_we <= "1"; |
bram_txtlp_writedata (31) <= flag1; --reserved |
bram_txtlp_writedata (30 downto 24) <= "1001010"; --type= rd completion |
bram_txtlp_writedata (23 downto 0) <= rxdw1_23_0; --various fields pcie_received_tlp (23 downto 0); |
elsif (bram_txtlp_writeaddress="000000000") then --header 2.dw |
bram_txtlp_we <= "1"; |
bram_txtlp_writedata (31 downto 16) <= cfg_completer_id; --completer ID |
bram_txtlp_writedata (15 downto 13) <= "000"; --status= UNSUPPORTED REQUEST *** |
bram_txtlp_writedata (12) <= '0'; --reserved |
bram_txtlp_writedata (11 downto 0) <= "000000000000"; --remaining byte count |
elsif (bram_txtlp_writeaddress="000000001") then --header 3.dw |
bram_txtlp_we <= "1"; |
bram_txtlp_writedata (31 downto 16) <= rxtlp_requesterid; --requester ID |
bram_txtlp_writedata (15 downto 8) <= pcie_rxtlp_tag ; --pcie_received_tlp (47 downto 40);--tag |
bram_txtlp_writedata (7) <= '0'; --reserved |
bram_txtlp_writedata (6 downto 2) <= rxtlp_decodedaddress(6 downto 2); --lower address |
bram_txtlp_writedata (1 downto 0) <= bit10(1 downto 0); --lower address |
else --data dwords |
bram_txtlp_we <= "0"; |
end if; |
--one pulse to start the ep-if statemachine, upon arriving to this state |
if (tlp_state_copy = tlp_state) then |
pcie_there_is_a_new_tlp_to_transmit <= '0'; |
else |
pcie_there_is_a_new_tlp_to_transmit <= '1'; |
end if; |
--back to idle when finished: |
if (pcie_tlp_tx_complete='1') then |
tlp_state <= "00000000"; |
end if; |
|
when others => --error |
tlp_state <= "00000000"; --go to state 0 |
end case; |
|
end if; |
end if; |
end process; --end tlp statemachine |
|
|
|
|
--byte enable encoding to wb_address bit1:0 |
--this does not swap the endian, since only the data is swapped in the pcie packets. |
process ( pciewb_localreset_n, rxtlp_firstdw_be ) |
begin |
if (pciewb_localreset_n = '0') then |
bit10(1 downto 0) <="00"; |
else |
if (rxtlp_firstdw_be ="0001") then |
bit10(1 downto 0) <= "00"; |
elsif (rxtlp_firstdw_be ="0010") then |
bit10(1 downto 0) <= "01"; |
elsif (rxtlp_firstdw_be ="0100") then |
bit10(1 downto 0) <= "10"; |
elsif (rxtlp_firstdw_be ="1000") then |
bit10(1 downto 0) <= "11"; |
elsif (rxtlp_firstdw_be ="0011") then |
bit10(1 downto 0) <= "00"; |
elsif (rxtlp_firstdw_be ="1100") then |
bit10(1 downto 0) <= "10"; |
elsif (rxtlp_firstdw_be ="1111") then |
bit10(1 downto 0) <= "00"; |
else --this should never happen |
bit10(1 downto 0) <= "00"; |
end if; |
end if; |
end process; |
|
|
|
|
|
-- INTERRUPTS: ------------------------------------------------------------------------- |
--to assert an interrupt, use the cfg_interrupt_assert_n pin. |
--datasheet text: |
--As shown in Figure 6-30, the user application first asserts cfg_interrupt_n and |
--cfg_interrupt_assert_n to assert the interrupt. The user application should select a |
--specific interrupt (INTA, INTB, INTC, or INTD) using cfg_interrupt_di[7:0] as shown |
--in Table 6-19. |
-- The core then asserts cfg_interrupt_rdy_n to indicate the interrupt has been accepted. |
--On the following clock cycle, the user application deasserts cfg_interrupt_n and, if the |
--Interrupt Disable bit in the PCI Command register is set to 0, the core sends an assert |
--interrupt message (Assert_INTA, Assert_INTB, and so forth). |
-- After the user application has determined that the interrupt has been serviced, it |
--asserts cfg_interrupt_n while deasserting cfg_interrupt_assert_n to deassert the |
--interrupt. The appropriate interrupt must be indicated via cfg_interrupt_di[7:0]. |
-- The core then asserts cfg_interrupt_rdy_n to indicate the interrupt deassertion has |
--been accepted. On the following clock cycle, the user application deasserts |
--cfg_interrupt_n and the core sends a deassert interrupt message (Deassert_INTA, |
--Deassert_INTB, and so forth). |
--cfg_interrupt_di[7:0] value Legacy Interrupt |
--00h INTA |
--01h INTB |
--02h INTC |
--03h INTD |
|
cfg_interrupt_di <= "00000000"; --intA used |
|
--prohibit IRQ assert when TLP state machine not idle. |
-- if an IRQ is asserted between a read request and completion, it causes an error in the endpoint block. |
-- added by StBa, AAC Microtec, 2012 |
irq_prohibit <= not tlpstm_isin_idle; |
|
process (pciewb_localreset_n, trn_clk, pcie_irq, pcieirq_state, |
cfg_interrupt_rdy_n) |
begin |
if (pciewb_localreset_n='0') then |
pcieirq_state <= "00000000"; |
cfg_interrupt_n <= '1'; |
cfg_interrupt_assert_n_1 <= '1'; |
else |
if (trn_clk'event and trn_clk = '1') then |
case ( pcieirq_state ) is |
|
--********** idle STATE ********** |
when "00000000" => --state 0 |
if (pcie_irq = '1' and irq_prohibit = '0') then |
pcieirq_state <= "00000001"; |
cfg_interrupt_n <= '0'; --active |
else |
cfg_interrupt_n <= '1'; --inactive |
end if; |
cfg_interrupt_assert_n_1 <= '0'; --0=assert, 1=deassert |
|
--********** assert STATE ********** |
when "00000001" => --state 1 |
if (cfg_interrupt_rdy_n ='0') then --ep accepted it |
cfg_interrupt_n <= '1'; --deassert the request |
pcieirq_state <= "00000010"; |
else |
cfg_interrupt_n <= '0'; --request INTA assertion |
end if; |
|
--********** pcie_irq kept asserted STATE ********** |
when "00000010" => --state 2 |
if (pcie_irq = '0' and irq_prohibit='0') then --pcie_irq gets deasserted |
pcieirq_state <= "00000011"; |
end if; |
cfg_interrupt_n <= '1'; --inactive |
cfg_interrupt_assert_n_1 <= '1'; --0=assert, 1=deassert |
|
--********** DEassert STATE ********** |
when "00000011" => --state 3 |
if (cfg_interrupt_rdy_n ='0') then --ep accepted it |
cfg_interrupt_n <= '1'; --deassert the request |
pcieirq_state <= "00000000"; |
else |
cfg_interrupt_n <= '0'; --request INTA DEassertion |
end if; |
|
when others => --error |
pcieirq_state <= "00000000"; --go to state 0 |
end case; |
end if; |
end if; |
end process; |
|
--this (little delay) is to fix a hold time violation created inside the pcie-ep ip: |
cfg_interrupt_assert_n <= cfg_interrupt_assert_n_1 or (not pciewb_localreset_n); |
|
|
|
|
|
|
-- -------- END OF FILE ------------------------------------------------------------------------------------- |
end Behavioral; |
|
|