1 |
2 |
dsmv |
-------------------------------------------------------------------------------
|
2 |
|
|
--
|
3 |
|
|
-- (c) Copyright 2009-2011 Xilinx, Inc. All rights reserved.
|
4 |
|
|
--
|
5 |
|
|
-- This file contains confidential and proprietary information
|
6 |
|
|
-- of Xilinx, Inc. and is protected under U.S. and
|
7 |
|
|
-- international copyright and other intellectual property
|
8 |
|
|
-- laws.
|
9 |
|
|
--
|
10 |
|
|
-- DISCLAIMER
|
11 |
|
|
-- This disclaimer is not a license and does not grant any
|
12 |
|
|
-- rights to the materials distributed herewith. Except as
|
13 |
|
|
-- otherwise provided in a valid license issued to you by
|
14 |
|
|
-- Xilinx, and to the maximum extent permitted by applicable
|
15 |
|
|
-- law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
|
16 |
|
|
-- WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
|
17 |
|
|
-- AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
|
18 |
|
|
-- BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
|
19 |
|
|
-- INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
|
20 |
|
|
-- (2) Xilinx shall not be liable (whether in contract or tort,
|
21 |
|
|
-- including negligence, or under any other theory of
|
22 |
|
|
-- liability) for any loss or damage of any kind or nature
|
23 |
|
|
-- related to, arising under or in connection with these
|
24 |
|
|
-- materials, including for any direct, or any indirect,
|
25 |
|
|
-- special, incidental, or consequential loss or damage
|
26 |
|
|
-- (including loss of data, profits, goodwill, or any type of
|
27 |
|
|
-- loss or damage suffered as a result of any action brought
|
28 |
|
|
-- by a third party) even if such damage or loss was
|
29 |
|
|
-- reasonably foreseeable or Xilinx had been advised of the
|
30 |
|
|
-- possibility of the same.
|
31 |
|
|
--
|
32 |
|
|
-- CRITICAL APPLICATIONS
|
33 |
|
|
-- Xilinx products are not designed or intended to be fail-
|
34 |
|
|
-- safe, or for use in any application requiring fail-safe
|
35 |
|
|
-- performance, such as life-support or safety devices or
|
36 |
|
|
-- systems, Class III medical devices, nuclear facilities,
|
37 |
|
|
-- applications related to the deployment of airbags, or any
|
38 |
|
|
-- other applications that could lead to death, personal
|
39 |
|
|
-- injury, or severe property or environmental damage
|
40 |
|
|
-- (individually and collectively, "Critical
|
41 |
|
|
-- Applications"). Customer assumes the sole risk and
|
42 |
|
|
-- liability of any use of Xilinx products in Critical
|
43 |
|
|
-- Applications, subject only to applicable laws and
|
44 |
|
|
-- regulations governing limitations on product liability.
|
45 |
|
|
--
|
46 |
|
|
-- THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
|
47 |
|
|
-- PART OF THIS FILE AT ALL TIMES.
|
48 |
|
|
--
|
49 |
|
|
-------------------------------------------------------------------------------
|
50 |
|
|
-- Project : Virtex-6 Integrated Block for PCI Express
|
51 |
|
|
-- File : axi_basic_rx_pipeline.vhd
|
52 |
|
|
-- Version : 2.3
|
53 |
|
|
--
|
54 |
|
|
-- Description:
|
55 |
|
|
-- TRN to AXI RX pipeline. Converts received data from TRN protocol to AXI.
|
56 |
|
|
--
|
57 |
|
|
-- Notes:
|
58 |
|
|
-- Optional notes section.
|
59 |
|
|
--
|
60 |
|
|
-- Hierarchical:
|
61 |
|
|
-- axi_basic_top
|
62 |
|
|
-- axi_basic_rx
|
63 |
|
|
-- axi_basic_rx_pipeline
|
64 |
|
|
--
|
65 |
|
|
-------------------------------------------------------------------------------
|
66 |
|
|
-- Library Declarations
|
67 |
|
|
--------------------------------------------------------------------------------
|
68 |
|
|
|
69 |
|
|
LIBRARY ieee;
|
70 |
|
|
USE ieee.std_logic_1164.all;
|
71 |
|
|
USE ieee.std_logic_unsigned.all;
|
72 |
|
|
|
73 |
|
|
|
74 |
|
|
ENTITY axi_basic_rx_pipeline IS
|
75 |
|
|
GENERIC (
|
76 |
|
|
C_DATA_WIDTH : INTEGER := 128; -- RX/TX interface data width
|
77 |
|
|
C_FAMILY : STRING := "X7"; -- Targeted FPGA family
|
78 |
|
|
TCQ : INTEGER := 1; -- Clock to Q time
|
79 |
|
|
|
80 |
|
|
C_REM_WIDTH : INTEGER := 1; -- trem/rrem width
|
81 |
|
|
C_STRB_WIDTH : INTEGER := 4 -- TSTRB width
|
82 |
|
|
);
|
83 |
|
|
PORT (
|
84 |
|
|
|
85 |
|
|
-- AXI RX
|
86 |
|
|
-------------
|
87 |
|
|
M_AXIS_RX_TDATA : OUT STD_LOGIC_VECTOR(C_DATA_WIDTH - 1 DOWNTO 0) ; -- RX data to user
|
88 |
|
|
M_AXIS_RX_TVALID : OUT STD_LOGIC ; -- RX data is valid
|
89 |
|
|
M_AXIS_RX_TREADY : IN STD_LOGIC ; -- RX ready for data
|
90 |
|
|
M_AXIS_RX_TSTRB : OUT STD_LOGIC_VECTOR(C_STRB_WIDTH - 1 DOWNTO 0) ; -- RX strobe byte enables
|
91 |
|
|
M_AXIS_RX_TLAST : OUT STD_LOGIC ; -- RX data is last
|
92 |
|
|
M_AXIS_RX_TUSER : OUT STD_LOGIC_VECTOR(21 DOWNTO 0) ; -- RX user signals
|
93 |
|
|
|
94 |
|
|
-- TRN RX
|
95 |
|
|
-------------
|
96 |
|
|
TRN_RD : IN STD_LOGIC_VECTOR(C_DATA_WIDTH - 1 DOWNTO 0) ; -- RX data from block
|
97 |
|
|
TRN_RSOF : IN STD_LOGIC ; -- RX start of packet
|
98 |
|
|
TRN_REOF : IN STD_LOGIC ; -- RX end of packet
|
99 |
|
|
TRN_RSRC_RDY : IN STD_LOGIC ; -- RX source ready
|
100 |
|
|
TRN_RDST_RDY : OUT STD_LOGIC ; -- RX destination ready
|
101 |
|
|
TRN_RSRC_DSC : IN STD_LOGIC ; -- RX source discontinue
|
102 |
|
|
TRN_RREM : IN STD_LOGIC_VECTOR(C_REM_WIDTH - 1 DOWNTO 0) ; -- RX remainder
|
103 |
|
|
TRN_RERRFWD : IN STD_LOGIC ; -- RX error forward
|
104 |
|
|
TRN_RBAR_HIT : IN STD_LOGIC_VECTOR(6 DOWNTO 0) ; -- RX BAR hit
|
105 |
|
|
TRN_RECRC_ERR : IN STD_LOGIC ; -- RX ECRC error
|
106 |
|
|
|
107 |
|
|
-- Null Inputs
|
108 |
|
|
-------------
|
109 |
|
|
NULL_RX_TVALID : IN STD_LOGIC ; -- NULL generated tvalid
|
110 |
|
|
NULL_RX_TLAST : IN STD_LOGIC ; -- NULL generated tlast
|
111 |
|
|
NULL_RX_TSTRB : IN STD_LOGIC_VECTOR(C_STRB_WIDTH - 1 DOWNTO 0) ; -- NULL generated tstrb
|
112 |
|
|
NULL_RDST_RDY : IN STD_LOGIC ; -- NULL generated rdst_rdy
|
113 |
|
|
NULL_IS_EOF : IN STD_LOGIC_VECTOR(4 DOWNTO 0) ; -- NULL generated is_eof
|
114 |
|
|
|
115 |
|
|
-- System
|
116 |
|
|
-------------
|
117 |
|
|
NP_COUNTER : OUT STD_LOGIC_VECTOR(2 DOWNTO 0) ; -- Non-posted counter
|
118 |
|
|
USER_CLK : IN STD_LOGIC ; -- user clock from block
|
119 |
|
|
USER_RST : IN STD_LOGIC -- user reset from block
|
120 |
|
|
);
|
121 |
|
|
END axi_basic_rx_pipeline;
|
122 |
|
|
|
123 |
|
|
ARCHITECTURE trans OF axi_basic_rx_pipeline IS
|
124 |
|
|
|
125 |
|
|
SIGNAL is_sof : STD_LOGIC_VECTOR(4 DOWNTO 0);
|
126 |
|
|
SIGNAL is_sof_prev : STD_LOGIC_VECTOR(4 DOWNTO 0);
|
127 |
|
|
|
128 |
|
|
SIGNAL is_eof : STD_LOGIC_VECTOR(4 DOWNTO 0);
|
129 |
|
|
SIGNAL is_eof_prev : STD_LOGIC_VECTOR(4 DOWNTO 0);
|
130 |
|
|
|
131 |
|
|
SIGNAL reg_tstrb : STD_LOGIC_VECTOR(C_STRB_WIDTH - 1 DOWNTO 0);
|
132 |
|
|
SIGNAL tstrb : STD_LOGIC_VECTOR(C_STRB_WIDTH - 1 DOWNTO 0);
|
133 |
|
|
SIGNAL tstrb_prev : STD_LOGIC_VECTOR(C_STRB_WIDTH - 1 DOWNTO 0);
|
134 |
|
|
|
135 |
|
|
SIGNAL reg_tlast : STD_LOGIC;
|
136 |
|
|
SIGNAL rsrc_rdy_filtered : STD_LOGIC;
|
137 |
|
|
|
138 |
|
|
SIGNAL trn_rd_DW_swapped : STD_LOGIC_VECTOR(C_DATA_WIDTH - 1 DOWNTO 0);
|
139 |
|
|
SIGNAL trn_rd_prev : STD_LOGIC_VECTOR(C_DATA_WIDTH - 1 DOWNTO 0);
|
140 |
|
|
|
141 |
|
|
SIGNAL data_hold : STD_LOGIC;
|
142 |
|
|
SIGNAL data_prev : STD_LOGIC;
|
143 |
|
|
|
144 |
|
|
SIGNAL trn_reof_prev : STD_LOGIC;
|
145 |
|
|
SIGNAL trn_rrem_prev : STD_LOGIC_VECTOR(C_REM_WIDTH - 1 DOWNTO 0);
|
146 |
|
|
SIGNAL trn_rsrc_rdy_prev : STD_LOGIC;
|
147 |
|
|
SIGNAL trn_rsrc_dsc_prev : STD_LOGIC;
|
148 |
|
|
SIGNAL trn_rsof_prev : STD_LOGIC;
|
149 |
|
|
SIGNAL trn_rbar_hit_prev : STD_LOGIC_VECTOR(6 DOWNTO 0);
|
150 |
|
|
SIGNAL trn_rerrfwd_prev : STD_LOGIC;
|
151 |
|
|
SIGNAL trn_recrc_err_prev : STD_LOGIC;
|
152 |
|
|
|
153 |
|
|
-- Null packet handling signals
|
154 |
|
|
SIGNAL null_mux_sel : STD_LOGIC;
|
155 |
|
|
SIGNAL trn_in_packet : STD_LOGIC;
|
156 |
|
|
SIGNAL dsc_flag : STD_LOGIC;
|
157 |
|
|
SIGNAL dsc_detect : STD_LOGIC;
|
158 |
|
|
SIGNAL reg_dsc_detect : STD_LOGIC;
|
159 |
|
|
SIGNAL trn_rsrc_dsc_d : STD_LOGIC;
|
160 |
|
|
|
161 |
|
|
-- Declare intermediate signals for referenced outputs
|
162 |
|
|
SIGNAL m_axis_rx_tdata_xhdl0 : STD_LOGIC_VECTOR(C_DATA_WIDTH - 1 DOWNTO 0);
|
163 |
|
|
SIGNAL m_axis_rx_tvalid_xhdl2 : STD_LOGIC;
|
164 |
|
|
SIGNAL m_axis_rx_tuser_xhdl1 : STD_LOGIC_VECTOR(21 DOWNTO 0);
|
165 |
|
|
SIGNAL trn_rdst_rdy_xhdl4 : STD_LOGIC;
|
166 |
|
|
SIGNAL mrd_lower : STD_LOGIC;
|
167 |
|
|
SIGNAL mrd_lk_lower : STD_LOGIC;
|
168 |
|
|
SIGNAL io_rdwr_lower : STD_LOGIC;
|
169 |
|
|
SIGNAL cfg_rdwr_lower : STD_LOGIC;
|
170 |
|
|
SIGNAL atomic_lower : STD_LOGIC;
|
171 |
|
|
SIGNAL np_pkt_lower : STD_LOGIC;
|
172 |
|
|
SIGNAL mrd_upper : STD_LOGIC;
|
173 |
|
|
SIGNAL mrd_lk_upper : STD_LOGIC;
|
174 |
|
|
SIGNAL io_rdwr_upper : STD_LOGIC;
|
175 |
|
|
SIGNAL cfg_rdwr_upper : STD_LOGIC;
|
176 |
|
|
SIGNAL atomic_upper : STD_LOGIC;
|
177 |
|
|
SIGNAL np_pkt_upper : STD_LOGIC;
|
178 |
|
|
SIGNAL pkt_accepted : STD_LOGIC;
|
179 |
|
|
SIGNAL reg_np_counter : STD_LOGIC_VECTOR(2 DOWNTO 0);
|
180 |
|
|
|
181 |
|
|
BEGIN
|
182 |
|
|
-- Drive referenced outputs
|
183 |
|
|
M_AXIS_RX_TDATA <= m_axis_rx_tdata_xhdl0;
|
184 |
|
|
M_AXIS_RX_TVALID <= m_axis_rx_tvalid_xhdl2;
|
185 |
|
|
M_AXIS_RX_TUSER <= m_axis_rx_tuser_xhdl1;
|
186 |
|
|
TRN_RDST_RDY <= trn_rdst_rdy_xhdl4;
|
187 |
|
|
|
188 |
|
|
-- Create "filtered" version of rsrc_rdy, where discontinued SOFs are removed
|
189 |
|
|
rsrc_rdy_filtered <= trn_rsrc_rdy AND (trn_in_packet OR (trn_rsof AND NOT trn_rsrc_dsc));
|
190 |
|
|
|
191 |
|
|
--------------------------------------------------------------------------------
|
192 |
|
|
-- Previous value buffer --
|
193 |
|
|
-- --------------------- --
|
194 |
|
|
-- We are inserting a pipeline stage in between TRN and AXI, which causes --
|
195 |
|
|
-- some issues with handshaking signals m_axis_rx_tready/trn_rdst_rdy. The --
|
196 |
|
|
-- added cycle of latency in the path causes the user design to fall behind --
|
197 |
|
|
-- the TRN interface whenever it throttles. --
|
198 |
|
|
-- --
|
199 |
|
|
-- To avoid loss of data, we must keep the previous value of all trn_r* --
|
200 |
|
|
-- signals in case the user throttles. --
|
201 |
|
|
--------------------------------------------------------------------------------
|
202 |
|
|
PROCESS (USER_CLK)
|
203 |
|
|
BEGIN
|
204 |
|
|
IF (USER_CLK'EVENT AND USER_CLK = '1') THEN
|
205 |
|
|
IF (USER_RST = '1') THEN
|
206 |
|
|
trn_rd_prev <= (others => '0')AFTER 1 ps;
|
207 |
|
|
trn_rsof_prev <= '0' AFTER (TCQ)*1 ps;
|
208 |
|
|
trn_rrem_prev <= (others => '0') AFTER (TCQ)*1 ps;
|
209 |
|
|
trn_rsrc_rdy_prev <= '0' AFTER 1 ps;
|
210 |
|
|
trn_rbar_hit_prev <= (others => '0') AFTER 1 ps;
|
211 |
|
|
trn_rerrfwd_prev <= '0' AFTER 1 ps;
|
212 |
|
|
trn_recrc_err_prev <= '0' AFTER 1 ps;
|
213 |
|
|
trn_reof_prev <= '0' AFTER 1 ps;
|
214 |
|
|
trn_rsrc_dsc_prev <= '0' AFTER 1 ps;
|
215 |
|
|
ELSE
|
216 |
|
|
-- prev buffer works by checking trn_rdst_rdy. When trn_rdst_rdy is
|
217 |
|
|
-- asserted, a new value is present on the interface.
|
218 |
|
|
|
219 |
|
|
IF (trn_rdst_rdy_xhdl4 = '1') THEN
|
220 |
|
|
trn_rd_prev <= trn_rd_DW_swapped AFTER (TCQ)*1 ps;
|
221 |
|
|
trn_rsof_prev <= TRN_RSOF AFTER (TCQ)*1 ps;
|
222 |
|
|
trn_rrem_prev <= TRN_RREM AFTER (TCQ)*1 ps;
|
223 |
|
|
trn_rbar_hit_prev <= TRN_RBAR_HIT AFTER (TCQ)*1 ps;
|
224 |
|
|
trn_rerrfwd_prev <= TRN_RERRFWD AFTER (TCQ)*1 ps;
|
225 |
|
|
trn_recrc_err_prev <= TRN_RECRC_ERR AFTER (TCQ)*1 ps;
|
226 |
|
|
trn_rsrc_rdy_prev <= rsrc_rdy_filtered AFTER (TCQ)*1 ps;
|
227 |
|
|
trn_reof_prev <= trn_reof AFTER (TCQ)*1 ps;
|
228 |
|
|
trn_rsrc_dsc_prev <= TRN_RSRC_DSC OR dsc_flag AFTER (TCQ)*1 ps;
|
229 |
|
|
END IF;
|
230 |
|
|
END IF;
|
231 |
|
|
END IF;
|
232 |
|
|
END PROCESS;
|
233 |
|
|
|
234 |
|
|
--------------------------------------------------------------------------------
|
235 |
|
|
-- Create TDATA
|
236 |
|
|
------------------------------------------------------------------------------
|
237 |
|
|
-- Convert TRN data format to AXI data format. AXI is DWORD swapped from TRN
|
238 |
|
|
-- 128-bit: 64-bit: 32-bit:
|
239 |
|
|
-- TRN DW0 maps to AXI DW3 TRN DW0 maps to AXI DW1 TNR DW0 maps to AXI DW0
|
240 |
|
|
-- TRN DW1 maps to AXI DW2 TRN DW1 maps to AXI DW0
|
241 |
|
|
-- TRN DW2 maps to AXI DW1
|
242 |
|
|
-- TRN DW3 maps to AXI DW0
|
243 |
|
|
|
244 |
|
|
xhdl7 : IF (C_DATA_WIDTH = 128) GENERATE
|
245 |
|
|
trn_rd_DW_swapped <= (TRN_RD(31 DOWNTO 0) & TRN_RD(63 DOWNTO 32) & TRN_RD(95 DOWNTO 64) & TRN_RD(127 DOWNTO 96));
|
246 |
|
|
END GENERATE;
|
247 |
|
|
--xhdl8 : IF (NOT(C_DATA_WIDTH = 128)) GENERATE
|
248 |
|
|
xhdl9 : IF (C_DATA_WIDTH = 64) GENERATE
|
249 |
|
|
trn_rd_DW_swapped <= (TRN_RD(31 DOWNTO 0) & TRN_RD(63 DOWNTO 32));
|
250 |
|
|
END GENERATE;
|
251 |
|
|
|
252 |
|
|
xhdl10 : IF (NOT(C_DATA_WIDTH = 64) AND NOT(C_DATA_WIDTH = 128)) GENERATE
|
253 |
|
|
trn_rd_DW_swapped <= TRN_RD;
|
254 |
|
|
END GENERATE;
|
255 |
|
|
--END GENERATE;
|
256 |
|
|
|
257 |
|
|
-- Create special buffer which locks in the proper value of TDATA depending
|
258 |
|
|
-- on whether the user is throttling or not. This buffer has three states:
|
259 |
|
|
--
|
260 |
|
|
-- HOLD state: TDATA maintains its current value
|
261 |
|
|
-- - the user has throttled the PCIe block
|
262 |
|
|
-- PREVIOUS state: the buffer provides the previous value on trn_rd
|
263 |
|
|
-- - the user has finished throttling, and is a little behind
|
264 |
|
|
-- the PCIe block
|
265 |
|
|
-- CURRENT state: the buffer passes the current value on trn_rd
|
266 |
|
|
-- - the user is caught up and ready to receive the latest
|
267 |
|
|
-- data from the PCIe block
|
268 |
|
|
|
269 |
|
|
PROCESS (USER_CLK)
|
270 |
|
|
BEGIN
|
271 |
|
|
IF (USER_CLK'EVENT AND USER_CLK = '1') THEN
|
272 |
|
|
IF (USER_RST = '1') THEN
|
273 |
|
|
m_axis_rx_tdata_xhdl0 <= (OTHERS=>'0') AFTER (TCQ)*1 ps;
|
274 |
|
|
ELSE
|
275 |
|
|
IF ((NOT(data_hold)) = '1') THEN
|
276 |
|
|
-- PREVIOUS state
|
277 |
|
|
IF (data_prev = '1') THEN
|
278 |
|
|
m_axis_rx_tdata_xhdl0 <= trn_rd_prev AFTER (TCQ)*1 ps;
|
279 |
|
|
-- CURRENT state
|
280 |
|
|
ELSE
|
281 |
|
|
m_axis_rx_tdata_xhdl0 <= trn_rd_DW_swapped AFTER (TCQ)*1 ps;
|
282 |
|
|
END IF;
|
283 |
|
|
END IF;
|
284 |
|
|
-- else HOLD state
|
285 |
|
|
END IF;
|
286 |
|
|
END IF;
|
287 |
|
|
END PROCESS;
|
288 |
|
|
|
289 |
|
|
-- Logic to instruct pipeline to hold its value
|
290 |
|
|
data_hold <= (NOT(M_AXIS_RX_TREADY) AND m_axis_rx_tvalid_xhdl2);
|
291 |
|
|
|
292 |
|
|
-- Logic to instruct pipeline to use previous bus values. Always use previous value after holding a value.
|
293 |
|
|
PROCESS (USER_CLK)
|
294 |
|
|
BEGIN
|
295 |
|
|
IF (USER_CLK'EVENT AND USER_CLK = '1') THEN
|
296 |
|
|
IF (USER_RST = '1') THEN
|
297 |
|
|
data_prev <= '0' AFTER (TCQ)*1 ps;
|
298 |
|
|
ELSE
|
299 |
|
|
data_prev <= data_hold AFTER (TCQ)*1 ps;
|
300 |
|
|
END IF;
|
301 |
|
|
END IF;
|
302 |
|
|
END PROCESS;
|
303 |
|
|
|
304 |
|
|
------------------------------------------------------------------------------
|
305 |
|
|
-- Create TVALID, TLAST, TSTRB, TUSER
|
306 |
|
|
-- -----------------------------------
|
307 |
|
|
-- Use the same strategy for these signals as for TDATA, except here we need
|
308 |
|
|
-- an extra provision for null packets.
|
309 |
|
|
------------------------------------------------------------------------------
|
310 |
|
|
PROCESS (USER_CLK)
|
311 |
|
|
BEGIN
|
312 |
|
|
IF (USER_CLK'EVENT AND USER_CLK = '1') THEN
|
313 |
|
|
IF (USER_RST = '1') THEN
|
314 |
|
|
m_axis_rx_tvalid_xhdl2 <= '0' AFTER (TCQ)*1 ps;
|
315 |
|
|
reg_tlast <= '0' AFTER (TCQ)*1 ps;
|
316 |
|
|
reg_tstrb <= (others => '1') AFTER (TCQ)*1 ps;
|
317 |
|
|
m_axis_rx_tuser_xhdl1 <= (others => '0') AFTER (TCQ)*1 ps;
|
318 |
|
|
ELSE
|
319 |
|
|
IF (data_hold = '0') THEN
|
320 |
|
|
-- If in a null packet, use null generated value
|
321 |
|
|
IF (null_mux_sel = '1') THEN
|
322 |
|
|
m_axis_rx_tvalid_xhdl2 <= NULL_RX_TVALID AFTER (TCQ)*1 ps;
|
323 |
|
|
reg_tlast <= NULL_RX_TLAST AFTER (TCQ)*1 ps;
|
324 |
|
|
reg_tstrb <= NULL_RX_TSTRB AFTER (TCQ)*1 ps;
|
325 |
|
|
m_axis_rx_tuser_xhdl1 <= (NULL_IS_EOF & "00000000000000000") AFTER (TCQ)*1 ps;
|
326 |
|
|
|
327 |
|
|
-- PREVIOUS state
|
328 |
|
|
ELSIF (data_prev = '1') THEN
|
329 |
|
|
m_axis_rx_tvalid_xhdl2 <= (trn_rsrc_rdy_prev OR dsc_flag) AFTER (TCQ)*1 ps;
|
330 |
|
|
reg_tlast <= trn_reof_prev AFTER (TCQ)*1 ps;
|
331 |
|
|
reg_tstrb <= tstrb_prev AFTER (TCQ)*1 ps;
|
332 |
|
|
m_axis_rx_tuser_xhdl1 <= (is_eof_prev & "00" & is_sof_prev & '0' & trn_rbar_hit_prev & trn_rerrfwd_prev & trn_recrc_err_prev) AFTER (TCQ)*1 ps;
|
333 |
|
|
-- TUSER bits [21:17] & TUSER bits [16:15] & TUSER bits [14:10] & TUSER bits [9] & TUSER bits [8:2] & TUSER bit [1] & TUSER bit [0]
|
334 |
|
|
|
335 |
|
|
-- CURRENT state
|
336 |
|
|
ELSE
|
337 |
|
|
|
338 |
|
|
m_axis_rx_tvalid_xhdl2 <= (rsrc_rdy_filtered OR dsc_flag) AFTER (TCQ)*1 ps;
|
339 |
|
|
reg_tlast <= TRN_REOF AFTER (TCQ)*1 ps;
|
340 |
|
|
reg_tstrb <= tstrb AFTER (TCQ)*1 ps;
|
341 |
|
|
m_axis_rx_tuser_xhdl1 <= (is_eof & "00" & is_sof & '0' & trn_rbar_hit & TRN_RERRFWD & TRN_RECRC_ERR) AFTER (TCQ)*1 ps;
|
342 |
|
|
-- TUSER bits [21:17] & TUSER bits [16:15] & TUSER bits [14:10] & TUSER bits [9] & TUSER bits [8:2] & TUSER bit [1] & TUSER bit [0]
|
343 |
|
|
END IF;
|
344 |
|
|
END IF;
|
345 |
|
|
-- else HOLD state
|
346 |
|
|
END IF;
|
347 |
|
|
END IF;
|
348 |
|
|
END PROCESS;
|
349 |
|
|
|
350 |
|
|
-- Hook up TLAST and TSTRB depending on interface width
|
351 |
|
|
xhdl11 : IF (C_DATA_WIDTH = 128) GENERATE
|
352 |
|
|
-- For 128-bit interface, don't pass TLAST and TSTRB to user (is_eof and is_data passed to user instead). reg_tlast is still used internally.
|
353 |
|
|
M_AXIS_RX_TLAST <= '0';
|
354 |
|
|
M_AXIS_RX_TSTRB <= (others => '1');
|
355 |
|
|
END GENERATE;
|
356 |
|
|
|
357 |
|
|
|
358 |
|
|
-- For 64/32-bit interface, pass TLAST to user.
|
359 |
|
|
xhdl12 : IF (NOT(C_DATA_WIDTH = 128)) GENERATE
|
360 |
|
|
M_AXIS_RX_TLAST <= reg_tlast;
|
361 |
|
|
M_AXIS_RX_TSTRB <= reg_tstrb;
|
362 |
|
|
END GENERATE;
|
363 |
|
|
|
364 |
|
|
--------------------------------------------------------------------------------
|
365 |
|
|
-- Create TSTRB ---
|
366 |
|
|
-- ------------ ---
|
367 |
|
|
-- Convert RREM to STRB. Here, we are converting the encoding method for the ---
|
368 |
|
|
-- location of the EOF from TRN flavor (rrem) to AXI (TSTRB). ---
|
369 |
|
|
-- ---
|
370 |
|
|
-- NOTE: for each configuration, we need two values of TSTRB, the current and---
|
371 |
|
|
-- previous values. The need for these two values is described below. ---
|
372 |
|
|
--------------------------------------------------------------------------------
|
373 |
|
|
xhdl13 : IF (C_DATA_WIDTH = 128) GENERATE
|
374 |
|
|
-- TLAST and TSTRB not used in 128-bit interface. is_sof and is_eof used instead.
|
375 |
|
|
tstrb <= x"0000";
|
376 |
|
|
tstrb_prev <= x"0000";
|
377 |
|
|
END GENERATE;
|
378 |
|
|
|
379 |
|
|
xhdl14 : IF (C_DATA_WIDTH /= 128) GENERATE
|
380 |
|
|
xhdl15 : IF (C_DATA_WIDTH = 64) GENERATE
|
381 |
|
|
-- 64-bit interface: contains 2 DWORDs per cycle, for a total of 8 bytes
|
382 |
|
|
-- TSTRB has only two possible values here, 0xFF or 0x0F
|
383 |
|
|
tstrb <= x"FF" WHEN (TRN_RREM = "11") ELSE x"0F";
|
384 |
|
|
tstrb_prev <= x"FF" WHEN (trn_rrem_prev = "11" ) ELSE x"0F";
|
385 |
|
|
END GENERATE;
|
386 |
|
|
xhdl16 : IF (C_DATA_WIDTH /= 64) GENERATE
|
387 |
|
|
-- 32-bit interface: contains 1 DWORD per cycle, for a total of 4 bytes
|
388 |
|
|
-- TSTRB is always 0xF in this case, due to the nature of the PCIe block
|
389 |
|
|
tstrb <= "1111";
|
390 |
|
|
tstrb_prev <= "1111";
|
391 |
|
|
END GENERATE;
|
392 |
|
|
END GENERATE;
|
393 |
|
|
|
394 |
|
|
------------------------------------------------------------------------------//
|
395 |
|
|
-- Create is_sof //
|
396 |
|
|
-- ------------- //
|
397 |
|
|
-- is_sof is a signal to the user indicating the location of SOF in TDATA . //
|
398 |
|
|
-- Due to inherent 64-bit alignment of packets from the block, the only //
|
399 |
|
|
-- possible values are: //
|
400 |
|
|
-- Value Valid data widths //
|
401 |
|
|
-- 5'b11000 (sof @ byte 8) 128 //
|
402 |
|
|
-- 5'b10000 (sof @ byte 0) 128, 64, 32 //
|
403 |
|
|
-- 5'b00000 (sof not present) 128, 64, 32 //
|
404 |
|
|
------------------------------------------------------------------------------//
|
405 |
|
|
xhdl17 : IF (C_DATA_WIDTH = 128) GENERATE
|
406 |
|
|
is_sof <= (((NOT(TRN_RSRC_DSC)) AND TRN_RSOF) & ((NOT(TRN_RREM(1))) AND TRN_RSOF ) & "000");
|
407 |
|
|
is_sof_prev <= (((trn_rsof_prev AND (NOT(trn_rsrc_dsc_prev)))) & (trn_rsof_prev AND (NOT(trn_rrem_prev(1)))) & "000");
|
408 |
|
|
-- bit 4: enable bit 3: sof @ byte 8? bit 2-0: hardwired 0
|
409 |
|
|
END GENERATE;
|
410 |
|
|
|
411 |
|
|
xhdl18 : IF (NOT(C_DATA_WIDTH = 128)) GENERATE
|
412 |
|
|
is_sof <= ((TRN_RSOF AND (NOT TRN_RSRC_DSC)) & "0000"); -- bit 4: enable, bits 3-0: hardwired 0
|
413 |
|
|
is_sof_prev <= ((trn_rsof_prev AND (NOT trn_rsrc_dsc_prev)) & "0000");
|
414 |
|
|
END GENERATE;
|
415 |
|
|
|
416 |
|
|
------------------------------------------------------------------------------//
|
417 |
|
|
-- Create is_eof //
|
418 |
|
|
-- ------------- //
|
419 |
|
|
-- is_eof is a signal to the user indicating the location of EOF in TDATA . //
|
420 |
|
|
-- Due to DWORD granularity of packets from the block, the only //
|
421 |
|
|
-- possible values are: //
|
422 |
|
|
-- Value Valid data widths //
|
423 |
|
|
-- 5'b11111 (eof @ byte 15) 128 //
|
424 |
|
|
-- 5'b11011 (eof @ byte 11) 128 //
|
425 |
|
|
-- 5'b10111 (eof @ byte 7) 128, 64 //
|
426 |
|
|
-- 5'b10011 (eof @ byte 3)` 128, 64, 32 //
|
427 |
|
|
-- 5'b00011 (eof not present) 128, 64, 32 //
|
428 |
|
|
------------------------------------------------------------------------------//
|
429 |
|
|
xhdl19 : IF (C_DATA_WIDTH = 128) GENERATE
|
430 |
|
|
is_eof <= (TRN_REOF & TRN_RREM & "11");
|
431 |
|
|
is_eof_prev <= (trn_reof_prev & trn_rrem_prev & "11");
|
432 |
|
|
-- bit 4: enable bit 3-2: encoded eof loc from block bit 1-0: hardwired 1
|
433 |
|
|
END GENERATE;
|
434 |
|
|
|
435 |
|
|
xhdl20 : IF (C_DATA_WIDTH = 64) GENERATE
|
436 |
|
|
is_eof <= (TRN_REOF & '0' & TRN_RREM & "11");
|
437 |
|
|
is_eof_prev <= (trn_reof_prev & '0' & trn_rrem_prev & "11");
|
438 |
|
|
-- bit 4: enable, bit 3: hardwired 0, bit 2: encoded eof loc from block, bit 1-0: hardwired 1
|
439 |
|
|
END GENERATE;
|
440 |
|
|
|
441 |
|
|
--------------------------------------------------------------------------------
|
442 |
|
|
xhdl20A : IF (C_DATA_WIDTH = 32) GENERATE
|
443 |
|
|
is_eof <= (TRN_REOF & "0011");
|
444 |
|
|
is_eof_prev <= (trn_reof_prev & "0011");
|
445 |
|
|
-- bit 4: enable, bit 3: hardwired 0, bit 2: encoded eof loc from block, bit 1-0: hardwired 1
|
446 |
|
|
END GENERATE;
|
447 |
|
|
|
448 |
|
|
|
449 |
|
|
-- Create trn_rdst_rdy --
|
450 |
|
|
--------------------------------------------------------------------------------
|
451 |
|
|
PROCESS (USER_CLK)
|
452 |
|
|
BEGIN
|
453 |
|
|
IF (USER_CLK'EVENT AND USER_CLK = '1') THEN
|
454 |
|
|
IF (USER_RST = '1') THEN
|
455 |
|
|
trn_rdst_rdy_xhdl4 <= '0' AFTER (TCQ)*1 ps;
|
456 |
|
|
ELSE
|
457 |
|
|
-- If in a null packet, use null generated value
|
458 |
|
|
IF (null_mux_sel = '1' AND M_AXIS_RX_TREADY = '1') THEN
|
459 |
|
|
trn_rdst_rdy_xhdl4 <= NULL_RDST_RDY AFTER (TCQ)*1 ps;
|
460 |
|
|
-- If a discontinue needs to be serviced, throttle the block until we are
|
461 |
|
|
-- ready to pad out the packet
|
462 |
|
|
ELSIF (dsc_flag = '1') THEN
|
463 |
|
|
trn_rdst_rdy_xhdl4 <= '0' AFTER (TCQ)*1 ps;
|
464 |
|
|
-- If in a packet, pass user back-pressure directly to block
|
465 |
|
|
ELSIF (m_axis_rx_tvalid_xhdl2 = '1') THEN
|
466 |
|
|
trn_rdst_rdy_xhdl4 <= M_AXIS_RX_TREADY AFTER (TCQ)*1 ps;
|
467 |
|
|
-- If idle, default to no back-pressure. We need to default to the
|
468 |
|
|
-- "ready to accept data" state to make sure we catch the first
|
469 |
|
|
-- clock of data of a new packet.
|
470 |
|
|
ELSE
|
471 |
|
|
trn_rdst_rdy_xhdl4 <= '1' AFTER (TCQ)*1 ps;
|
472 |
|
|
END IF;
|
473 |
|
|
END IF;
|
474 |
|
|
END IF;
|
475 |
|
|
END PROCESS;
|
476 |
|
|
|
477 |
|
|
------------------------------------------------------------------------------//
|
478 |
|
|
-- Create null_mux_sel //
|
479 |
|
|
-- null_mux_sel is the signal used to detect a discontinue situation and //
|
480 |
|
|
-- mux in the null packet generated in rx_null_gen. Only mux in null data //
|
481 |
|
|
-- when not at the beginningof a packet. SOF discontinues do not require //
|
482 |
|
|
-- padding, as the whole packet is simply squashed instead. //
|
483 |
|
|
------------------------------------------------------------------------------//
|
484 |
|
|
PROCESS (USER_CLK)
|
485 |
|
|
BEGIN
|
486 |
|
|
IF (USER_CLK'EVENT AND USER_CLK = '1') THEN
|
487 |
|
|
IF (USER_RST = '1') THEN
|
488 |
|
|
null_mux_sel <= '0' AFTER (TCQ)*1 ps;
|
489 |
|
|
ELSE
|
490 |
|
|
-- NULL packet done
|
491 |
|
|
IF (null_mux_sel = '1' AND NULL_RX_TLAST = '1' AND M_AXIS_RX_TREADY = '1') THEN
|
492 |
|
|
null_mux_sel <= '0' AFTER (TCQ)*1 ps;
|
493 |
|
|
-- Discontinue detected and we're in packet, so switch to NULL packet
|
494 |
|
|
ELSIF (dsc_flag = '1' AND data_hold = '0') THEN
|
495 |
|
|
null_mux_sel <= '1' AFTER (TCQ)*1 ps;
|
496 |
|
|
END IF;
|
497 |
|
|
END IF;
|
498 |
|
|
END IF;
|
499 |
|
|
END PROCESS;
|
500 |
|
|
|
501 |
|
|
------------------------------------------------------------------------------//
|
502 |
|
|
-- Create discontinue tracking signals //
|
503 |
|
|
------------------------------------------------------------------------------//
|
504 |
|
|
-- Create signal trn_in_packet, which is needed to validate trn_rsrc_dsc. We
|
505 |
|
|
-- should ignore trn_rsrc_dsc when it's asserted out-of-packet.
|
506 |
|
|
PROCESS (USER_CLK)
|
507 |
|
|
BEGIN
|
508 |
|
|
IF (USER_CLK'EVENT AND USER_CLK = '1') THEN
|
509 |
|
|
IF (USER_RST = '1') THEN
|
510 |
|
|
trn_in_packet <= '0' AFTER (TCQ)*1 ps;
|
511 |
|
|
ELSE
|
512 |
|
|
IF ((TRN_RSOF = '1') AND (NOT(TRN_REOF = '1')) AND rsrc_rdy_filtered = '1' AND trn_rdst_rdy_xhdl4 = '1') THEN
|
513 |
|
|
trn_in_packet <= '1' AFTER (TCQ)*1 ps;
|
514 |
|
|
ELSIF (TRN_RSRC_DSC = '1') THEN
|
515 |
|
|
trn_in_packet <= '0' AFTER (TCQ)*1 ps;
|
516 |
|
|
ELSIF (TRN_REOF= '1' AND (NOT(TRN_RSOF= '1')) AND TRN_RSRC_RDY = '1' AND trn_rdst_rdy_xhdl4 = '1') THEN
|
517 |
|
|
trn_in_packet <= '0';
|
518 |
|
|
END IF;
|
519 |
|
|
END IF;
|
520 |
|
|
END IF;
|
521 |
|
|
END PROCESS;
|
522 |
|
|
|
523 |
|
|
-- Create dsc_flag, which identifies and stores mid-packet discontinues that
|
524 |
|
|
-- require null packet padding. This signal is edge sensitive to trn_rsrc_dsc,
|
525 |
|
|
-- to make sure we don't service the same dsc twice in the event that
|
526 |
|
|
-- trn_rsrc_dsc stays asserted for longer than it takes to pad out the packet.
|
527 |
|
|
|
528 |
|
|
dsc_detect <= TRN_RSRC_DSC and (not(trn_rsrc_dsc_d)) and trn_in_packet and ((not(TRN_RSOF)) or TRN_REOF) and (not(trn_rdst_rdy_xhdl4 and TRN_REOF));
|
529 |
|
|
|
530 |
|
|
PROCESS (USER_CLK,USER_RST)
|
531 |
|
|
BEGIN
|
532 |
|
|
IF (USER_CLk'EVENT AND USER_CLK = '1') THEN
|
533 |
|
|
IF (USER_RST = '1') THEN
|
534 |
|
|
reg_dsc_detect <= '0' AFTER (TCQ)*1 ps;
|
535 |
|
|
trn_rsrc_dsc_d <= '0' AFTER (TCQ)*1 ps;
|
536 |
|
|
ELSE
|
537 |
|
|
IF (dsc_detect = '1') THEN
|
538 |
|
|
reg_dsc_detect <= '1' AFTER (TCQ)*1 ps;
|
539 |
|
|
ELSIF (null_mux_sel = '1') THEN
|
540 |
|
|
reg_dsc_detect <= '0' AFTER (TCQ)*1 ps;
|
541 |
|
|
END IF;
|
542 |
|
|
|
543 |
|
|
trn_rsrc_dsc_d <= TRN_RSRC_DSC AFTER (TCQ)*1 ps;
|
544 |
|
|
END IF;
|
545 |
|
|
END IF;
|
546 |
|
|
END PROCESS;
|
547 |
|
|
|
548 |
|
|
dsc_flag <= dsc_detect OR reg_dsc_detect;
|
549 |
|
|
|
550 |
|
|
--------------------------------------------------------------------------------
|
551 |
|
|
-- Create np_counter (V6 128-bit only). This counter tells the V6 128-bit --
|
552 |
|
|
-- interface core how many NP packets have left the RX pipeline. The V6 --
|
553 |
|
|
-- 128-bit interface uses this count to perform rnp_ok modulation. --
|
554 |
|
|
--------------------------------------------------------------------------------
|
555 |
|
|
|
556 |
|
|
xhdl21 : IF ((C_FAMILY = "V6") AND (C_DATA_WIDTH = 128)) GENERATE
|
557 |
|
|
-- Look for NP packets beginning on lower (i.e. unaligned) start
|
558 |
|
|
mrd_lower <= '1' WHEN (m_axis_rx_tdata_xhdl0(92 DOWNTO 88) = "00000" AND m_axis_rx_tdata_xhdl0(94) = '0') ELSE '0';
|
559 |
|
|
mrd_lk_lower <= '1' WHEN (m_axis_rx_tdata_xhdl0(92 DOWNTO 88) = "00001") ELSE '0';
|
560 |
|
|
io_rdwr_lower <= '1' WHEN (m_axis_rx_tdata_xhdl0(92 DOWNTO 88) = "00010") ELSE '0';
|
561 |
|
|
cfg_rdwr_lower <= '1' WHEN (m_axis_rx_tdata_xhdl0(92 DOWNTO 89) = "0010") ELSE '0';
|
562 |
|
|
atomic_lower <= '1' WHEN (m_axis_rx_tdata_xhdl0(91 DOWNTO 90) = "11" AND m_axis_rx_tdata_xhdl0(94) = '1') ELSE '0';
|
563 |
|
|
|
564 |
|
|
np_pkt_lower <= '1' WHEN ((mrd_lower = '1' OR
|
565 |
|
|
mrd_lk_lower = '1' OR
|
566 |
|
|
io_rdwr_lower = '1' OR
|
567 |
|
|
cfg_rdwr_lower = '1' OR
|
568 |
|
|
atomic_lower = '1') AND m_axis_rx_tuser_xhdl1(13) = '1') ELSE '0';
|
569 |
|
|
|
570 |
|
|
-- Look for NP packets beginning on upper (i.e. aligned) start
|
571 |
|
|
mrd_upper <= '1' WHEN (m_axis_rx_tdata_xhdl0(28 DOWNTO 24) = "00000" AND m_axis_rx_tdata_xhdl0(30) = '0') ELSE '0';
|
572 |
|
|
mrd_lk_upper <= '1' WHEN (m_axis_rx_tdata_xhdl0(28 DOWNTO 24) = "00001") ELSE '0';
|
573 |
|
|
io_rdwr_upper <= '1' WHEN (m_axis_rx_tdata_xhdl0(28 DOWNTO 24) = "00010") ELSE '0';
|
574 |
|
|
cfg_rdwr_upper <= '1' WHEN (m_axis_rx_tdata_xhdl0(28 DOWNTO 25) = "0010") ELSE '0';
|
575 |
|
|
atomic_upper <= '1' WHEN (m_axis_rx_tdata_xhdl0(27 DOWNTO 26) = "11" AND m_axis_rx_tdata_xhdl0(30) = '1') ELSE '0';
|
576 |
|
|
|
577 |
|
|
np_pkt_upper <= '1' WHEN ((mrd_upper = '1' OR
|
578 |
|
|
mrd_lk_upper = '1' OR
|
579 |
|
|
io_rdwr_upper = '1' OR
|
580 |
|
|
cfg_rdwr_upper = '1' OR
|
581 |
|
|
atomic_upper = '1') AND m_axis_rx_tuser_xhdl1(13) = '0') ELSE '0';
|
582 |
|
|
|
583 |
|
|
pkt_accepted <= '1' WHEN (m_axis_rx_tuser_xhdl1(14) = '1' AND M_AXIS_RX_TREADY = '1' AND m_axis_rx_tvalid_xhdl2 = '1') ELSE '0';
|
584 |
|
|
|
585 |
|
|
-- Increment counter whenever an NP packet leaves the RX pipeline
|
586 |
|
|
PROCESS (USER_CLK)
|
587 |
|
|
BEGIN
|
588 |
|
|
IF (USER_CLK'EVENT AND USER_CLK = '1') THEN
|
589 |
|
|
IF (USER_RST = '1') THEN
|
590 |
|
|
reg_np_counter <= "000" AFTER (TCQ)*1 ps;
|
591 |
|
|
ELSE
|
592 |
|
|
IF ((np_pkt_lower = '1' OR np_pkt_upper = '1') AND pkt_accepted = '1') THEN
|
593 |
|
|
reg_np_counter <= reg_np_counter + "001" AFTER (TCQ)*1 ps;
|
594 |
|
|
END IF;
|
595 |
|
|
END IF;
|
596 |
|
|
END IF;
|
597 |
|
|
END PROCESS;
|
598 |
|
|
|
599 |
|
|
NP_COUNTER <= reg_np_counter;
|
600 |
|
|
END GENERATE;
|
601 |
|
|
|
602 |
|
|
xhdl22 : IF (NOT(C_FAMILY = "V6" AND C_DATA_WIDTH = 128)) GENERATE
|
603 |
|
|
NP_COUNTER <= "000";
|
604 |
|
|
END GENERATE;
|
605 |
|
|
END trans;
|
606 |
|
|
|
607 |
|
|
|