Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: ilupeuMalReqPEUStr.vr | |
4 | // Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved | |
5 | // 4150 Network Circle, Santa Clara, California 95054, U.S.A. | |
6 | // | |
7 | // * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
8 | // | |
9 | // This program is free software; you can redistribute it and/or modify | |
10 | // it under the terms of the GNU General Public License as published by | |
11 | // the Free Software Foundation; version 2 of the License. | |
12 | // | |
13 | // This program is distributed in the hope that it will be useful, | |
14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | // GNU General Public License for more details. | |
17 | // | |
18 | // You should have received a copy of the GNU General Public License | |
19 | // along with this program; if not, write to the Free Software | |
20 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 | // | |
22 | // For the avoidance of doubt, and except that if any non-GPL license | |
23 | // choice is available it will apply instead, Sun elects to use only | |
24 | // the General Public License version 2 (GPLv2) at this time for any | |
25 | // software where a choice of GPL license versions is made | |
26 | // available with the language indicating that GPLv2 or any later version | |
27 | // may be used, or where a choice of which version of the GPL is applied is | |
28 | // otherwise unspecified. | |
29 | // | |
30 | // Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
31 | // CA 95054 USA or visit www.sun.com if you need additional information or | |
32 | // have any questions. | |
33 | // | |
34 | // ========== Copyright Header End ============================================ | |
35 | class MalReqPEUStr extends PEUStrBase | |
36 | { | |
37 | local bit f_typeSpecified; // Was a bad-boy type supplied? | |
38 | local bit [1:0] f_fmt; // The bad format | |
39 | local bit [4:0] f_type; // The bad type | |
40 | local bit f_lenSpecified; // Was a TLP length supplied? | |
41 | local integer f_len; // A requested TLP length | |
42 | local integer f_cross4K; // By what amount do we cross 4K | |
43 | local integer f_adjustLen; // The delta to the true length | |
44 | local integer f_errQueue; // A mailbox for bad pkt headers | |
45 | local bit f_tdSpecified; // Was the TD supplied? | |
46 | local bit f_tdFieldValue; // The TD value | |
47 | local bit [7:0] f_msgcode; // Msg code (for Msg requests) | |
48 | local bit f_mcSpecified; // Was the msg code supplied? | |
49 | local bit [2:0] f_TC; | |
50 | local bit f_TCSpecified; | |
51 | local bit f_dwbeSpecified; | |
52 | local bit [3:0] f_firstDWBE; | |
53 | local bit [3:0] f_lastDWBE; | |
54 | local bit f_QWbndy; | |
55 | ||
56 | task new( PEUTestEnv a_env ) | |
57 | { | |
58 | super.new( a_env ); | |
59 | f_typeSpecified = 0; | |
60 | f_lenSpecified = 0; | |
61 | f_errQueue = 0; | |
62 | f_adjustLen = 0; | |
63 | f_cross4K = 0; | |
64 | f_dwbeSpecified = 0; | |
65 | f_QWbndy = 1'bx; | |
66 | ||
67 | f_tdSpecified = 0; | |
68 | } /* end new */ | |
69 | ||
70 | function bit SetType( bit [1:0] a_fmt, bit [4:0] a_type ) | |
71 | { | |
72 | bit isInvalid; | |
73 | ||
74 | case ( a_fmt ) | |
75 | { | |
76 | 2'b00: isInvalid = !( PEC_PCI__TYPE_VALID_00 & ( 1 << a_type ) ); | |
77 | 2'b01: isInvalid = !( PEC_PCI__TYPE_VALID_01 & ( 1 << a_type ) ); | |
78 | 2'b10: isInvalid = !( PEC_PCI__TYPE_VALID_10 & ( 1 << a_type ) ); | |
79 | 2'b11: isInvalid = !( PEC_PCI__TYPE_VALID_11 & ( 1 << a_type ) ); | |
80 | } | |
81 | if ( isInvalid ) | |
82 | { | |
83 | f_typeSpecified = 1; | |
84 | f_type = a_type; | |
85 | f_fmt = a_fmt; | |
86 | } | |
87 | SetType = isInvalid; | |
88 | } /* end SetType */ | |
89 | ||
90 | task SetLength( integer a_length ) | |
91 | { | |
92 | f_len= a_length; | |
93 | f_lenSpecified = 1; | |
94 | } /* end SetLength */ | |
95 | ||
96 | task AdjustLen( integer a_lengthDelta ) | |
97 | { | |
98 | f_adjustLen = a_lengthDelta; | |
99 | } /* end AdjustLen */ | |
100 | ||
101 | task Cross4K( integer a_dwCount ) | |
102 | { | |
103 | f_cross4K = a_dwCount; | |
104 | } /* end AdjustLen */ | |
105 | ||
106 | function bit SetDWBE( bit [3:0] firstDWBE, bit [3:0] lastDWBE, | |
107 | (bit QWbndy=1'bx) ) | |
108 | { | |
109 | bit isContiguous; | |
110 | bit isInvalid; | |
111 | ||
112 | // DWBEs are bad if lastDWBE != 0 and len = 1, or either = 0 and len > 1 | |
113 | // DWBEs are bad if not contiguous and len > 2 or len = 2 not on QW bndy | |
114 | // We'll force a length to make the DWBE bad if one has not been specified | |
115 | isContiguous = ( firstDWBE == 4'b1000 || firstDWBE == 4'b1100 || | |
116 | firstDWBE == 4'b1110 || firstDWBE == 4'b1111 ) | |
117 | && ( lastDWBE == 4'b0001 || lastDWBE == 4'b0011 || | |
118 | lastDWBE == 4'b0111 || lastDWBE == 4'b1111 ); | |
119 | if ( f_lenSpecified ) | |
120 | { | |
121 | if ( f_len == 1 ) | |
122 | isInvalid = lastDWBE != 0; | |
123 | else if ( f_len == 2 && QWbndy ) | |
124 | isInvalid = !firstDWBE || !lastDWBE; | |
125 | else | |
126 | isInvalid = !isContiguous; | |
127 | } | |
128 | else | |
129 | { | |
130 | f_lenSpecified = 1; | |
131 | f_len = isContiguous ? 1 : 4; | |
132 | isInvalid = 1; | |
133 | } | |
134 | ||
135 | if ( isInvalid ) | |
136 | { | |
137 | f_dwbeSpecified = 1; | |
138 | f_firstDWBE = firstDWBE; | |
139 | f_lastDWBE = lastDWBE; | |
140 | f_QWbndy = QWbndy; | |
141 | if ( f_len == 2 && QWbndy !== 1'b1 ) f_QWbndy = 1'b0; | |
142 | } | |
143 | ||
144 | SetDWBE = isInvalid; | |
145 | } /* end SetDWBE */ | |
146 | ||
147 | task SetErrQueue( integer a_queue ) | |
148 | { | |
149 | f_errQueue = a_queue; | |
150 | } /* end SetErrQueue */ | |
151 | ||
152 | task SetTD( bit a_TDValue ) | |
153 | { | |
154 | f_tdFieldValue = a_TDValue; | |
155 | f_tdSpecified = 1; | |
156 | } /* end SetTD */ | |
157 | ||
158 | function bit SetField( string FieldName, bit [9:0] FieldValue ) | |
159 | { | |
160 | // return value of 1'b1 indicates something went wrong | |
161 | case ( FieldName ) { | |
162 | "FmtType" : { | |
163 | f_type = FieldValue[ 4:0 ]; | |
164 | f_fmt = FieldValue[ 6:5 ]; | |
165 | f_typeSpecified = 1; | |
166 | ||
167 | case ( f_fmt ) { | |
168 | 2'b00: SetField = !( PEC_PCI__TYPE_VALID_00 & ( 1 << f_type ) ); | |
169 | 2'b01: SetField = !( PEC_PCI__TYPE_VALID_01 & ( 1 << f_type ) ); | |
170 | 2'b10: SetField = !( PEC_PCI__TYPE_VALID_10 & ( 1 << f_type ) ); | |
171 | 2'b11: SetField = !( PEC_PCI__TYPE_VALID_11 & ( 1 << f_type ) ); | |
172 | } | |
173 | } | |
174 | "MsgCode" : { | |
175 | f_msgcode = FieldValue; | |
176 | f_mcSpecified = 1; | |
177 | SetField = 1'b0; | |
178 | } | |
179 | "TC" : { | |
180 | f_TC = FieldValue[ 2:0 ]; | |
181 | f_TCSpecified = 1; | |
182 | SetField = 1'b0; | |
183 | } | |
184 | default : | |
185 | SetField = 1'b1; | |
186 | } | |
187 | } /* end SetField */ | |
188 | ||
189 | task Execute() | |
190 | { | |
191 | bit genWrReq; // Is a write request in order? | |
192 | bit[PEC_PCI__HDR] ingressHdr; // The ingress TLP's header | |
193 | integer ingressData; // A payload descriptor | |
194 | bit[7:0] ingressTag; // The tag for the TLP | |
195 | bit[63:0] addr_bits; | |
196 | bit[9:0] length_bits; | |
197 | integer tlpLen; | |
198 | bit [63:0] diagCsr; | |
199 | bit [31:0] tempDenaliData; | |
200 | bit [31:0] tempDenaliData1; | |
201 | ||
202 | // First, get in line for a DMA tag... | |
203 | f_env.allocDmaTag( ingressTag ); | |
204 | printf( "MalReq: tag=%h", ingressTag ); | |
205 | if ( f_lenSpecified ) printf( " len=%0d", f_len ); | |
206 | if ( f_cross4K != 0 ) printf( " cross4K=%0d", f_cross4K ); | |
207 | if ( f_dwbeSpecified ) printf( " firstDWBE=%b lastDWBE=%b", | |
208 | f_firstDWBE, f_lastDWBE ); | |
209 | if( f_typeSpecified ) printf( " f_fmt=%0h ",f_fmt ); | |
210 | printf( "\n" ); | |
211 | ||
212 | // Then build a TLP. | |
213 | // Either a write or a read (with or | |
214 | // without data. | |
215 | if ( f_typeSpecified ) | |
216 | { | |
217 | ingressHdr[PEC_PCI__FMT] = f_fmt; | |
218 | genWrReq = ingressHdr[PEC_PCI__FMT_DATA]; | |
219 | } | |
220 | else | |
221 | genWrReq = urandom() % 2; | |
222 | ||
223 | ||
224 | //If this is a cross4K test then set the length so valid DWBE's are generated | |
225 | if ( f_cross4K != 0 ) { | |
226 | // f_cross4K specifies the number of DWs | |
227 | // to cross the next 4KB boundary by | |
228 | // pkt length greater than or equal to | |
229 | // the amount to cross boundary by | |
230 | length_bits = (urandom() % 15) + 1; | |
231 | f_len = length_bits + f_cross4K; | |
232 | f_lenSpecified = 1; | |
233 | } | |
234 | ||
235 | ||
236 | ||
237 | ||
238 | if ( genWrReq ) | |
239 | { | |
240 | if ( f_lenSpecified ) | |
241 | f_env.genIngressWrReq( ingressTag, ingressHdr, ingressData, f_len ); | |
242 | else | |
243 | f_env.genIngressWrReq( ingressTag, ingressHdr, ingressData ); | |
244 | } | |
245 | else | |
246 | { | |
247 | if ( f_lenSpecified ) | |
248 | f_env.genIngressRdReq( ingressTag, ingressHdr, ingressData, f_len ); | |
249 | else | |
250 | f_env.genIngressRdReq( ingressTag, ingressHdr, ingressData ); | |
251 | } | |
252 | //Denali can hold a TLP from being transmitted if a previous TLP | |
253 | // with the same tag and Request ID has not completed yet. This only | |
254 | // should happen with error TLPs. To help with this make all bad REQs | |
255 | // PEC_PCI__REQ_ID[0] = 1 | |
256 | ingressHdr[80] = 1'b1; | |
257 | ||
258 | ||
259 | // ...and then pollute the request as | |
260 | // directed by the caller. | |
261 | if ( f_typeSpecified ) | |
262 | { | |
263 | ingressHdr[PEC_PCI__FMT] = f_fmt; | |
264 | ingressHdr[PEC_PCI__TYPE] = f_type; | |
265 | } | |
266 | if ( f_dwbeSpecified ) | |
267 | { | |
268 | if ( f_QWbndy ) f_env.setAddrBndy( ingressHdr, 0, 8 ); | |
269 | if ( !f_QWbndy ) f_env.setAddrBndy( ingressHdr, 4, 8 ); | |
270 | ingressHdr[PEC_PCI__FIRST_DWBE] = f_firstDWBE; | |
271 | ingressHdr[PEC_PCI__LAST_DWBE] = f_lastDWBE; | |
272 | } | |
273 | if ( f_cross4K != 0 ) { | |
274 | if ( ingressHdr[PEC_PCI__TYPE] != PEC_PCI__TYPE_MEM ) | |
275 | { | |
276 | printf( "Forcing req-type to 'memory' due to 4KB crossing\n" ); | |
277 | ingressHdr[PEC_PCI__TYPE] = PEC_PCI__TYPE_MEM; | |
278 | } | |
279 | ||
280 | ||
281 | // f_cross4K specifies the number of DWs | |
282 | // to cross the next 4KB boundary by | |
283 | // pkt length greater than or equal to | |
284 | // the amount to cross boundary by | |
285 | /* Do this before calling genIngressXxReq so valid DWBEs get generated | |
286 | length_bits = (urandom() % 15) + 1; | |
287 | ingressHdr[PEC_PCI__LEN] = length_bits + f_cross4K; | |
288 | */ | |
289 | ingressHdr[PEC_PCI__LEN] = f_len; | |
290 | if( ingressHdr[PEC_PCI__FMT_4DW] ) { | |
291 | addr_bits = ingressHdr[PEC_PCI__ADDR]; | |
292 | addr_bits[11:2] = 1024 - length_bits; | |
293 | ingressHdr[PEC_PCI__ADDR] = addr_bits; | |
294 | } | |
295 | else { | |
296 | addr_bits = {{32'h00000000},ingressHdr[PEC_PCI__ADDR32]}; | |
297 | addr_bits[11:2] = 1024 - length_bits; | |
298 | addr_bits[1:0] = 0; //if f_typeSpecified make sure the lowest 2 addr bits are 0 | |
299 | ingressHdr[PEC_PCI__ADDR32] = addr_bits[31:0]; | |
300 | } | |
301 | } | |
302 | ||
303 | //If this is a memory request make sure lower 2 address bits are 0 for header capture | |
304 | // since Denali sets them to 0 automatically | |
305 | if( ingressHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_MEM ){ | |
306 | if( ingressHdr[PEC_PCI__FMT_4DW] ) { | |
307 | ingressHdr[1:0] = 0; | |
308 | }else{ | |
309 | ingressHdr[33:32] = 0; | |
310 | } | |
311 | } | |
312 | ||
313 | ||
314 | if ( f_tdSpecified ) | |
315 | ingressHdr[PEC_PCI__TD] = f_tdFieldValue; | |
316 | ||
317 | if ( f_mcSpecified ){ | |
318 | ingressHdr[PEC_PCI__MSG_CODE] = f_msgcode; | |
319 | ingressHdr[PEC_PCI__ATTR] = 0; | |
320 | ingressHdr[PEC_PCI__ADDR] = 0; //DW3 and DW4 = 0 | |
321 | ||
322 | if( f_msgcode == PEC_PCI__MSG_CODE_ASSERT_INTA || | |
323 | f_msgcode == PEC_PCI__MSG_CODE_ASSERT_INTB || | |
324 | f_msgcode == PEC_PCI__MSG_CODE_ASSERT_INTC || | |
325 | f_msgcode == PEC_PCI__MSG_CODE_ASSERT_INTD || | |
326 | f_msgcode == PEC_PCI__MSG_CODE_DEASSERT_INTA || | |
327 | f_msgcode == PEC_PCI__MSG_CODE_DEASSERT_INTB || | |
328 | f_msgcode == PEC_PCI__MSG_CODE_DEASSERT_INTC || | |
329 | f_msgcode == PEC_PCI__MSG_CODE_DEASSERT_INTD ){ | |
330 | ||
331 | ingressHdr[PEC_PCI__TYPE] = 5'b10100; | |
332 | } | |
333 | else if( f_msgcode == PEC_PCI__MSG_CODE_PM_PME || | |
334 | f_msgcode == PEC_PCI__MSG_CODE_ERR_COR || | |
335 | f_msgcode == PEC_PCI__MSG_CODE_ERR_NONFATAL || | |
336 | f_msgcode == PEC_PCI__MSG_CODE_ERR_FATAL ){ | |
337 | ingressHdr[PEC_PCI__TYPE] = 5'b10000; | |
338 | } | |
339 | else if( f_msgcode == PEC_PCI__MSG_CODE_PM_TO_ACK ){ | |
340 | ingressHdr[PEC_PCI__TYPE] = 5'b10101; | |
341 | } | |
342 | ||
343 | if( !ingressHdr[PEC_PCI__FMT_DATA] ){ | |
344 | ingressHdr[PEC_PCI__LEN] = 0; | |
345 | } | |
346 | } | |
347 | ||
348 | if ( f_TCSpecified ) | |
349 | ingressHdr[PEC_PCI__TC] = f_TC; | |
350 | ||
351 | // Don't allow the truncated TLP to be | |
352 | // less than 3DW. | |
353 | if ( f_adjustLen < 0 && !ingressHdr[PEC_PCI__FMT_DATA] ) | |
354 | { | |
355 | tlpLen = 3 + ingressHdr[PEC_PCI__FMT_4DW] + ingressHdr[PEC_PCI__TD]; | |
356 | if ( tlpLen + f_adjustLen < 3 ) | |
357 | printf( "MalReq (cycle %0d) Adding TD/addr to TLP to reach 3DW...\n", | |
358 | get_cycle() ); | |
359 | if ( tlpLen + f_adjustLen < 3 && !ingressHdr[PEC_PCI__TD] ) | |
360 | { | |
361 | tlpLen = tlpLen + 1; | |
362 | ingressHdr[PEC_PCI__TD] = 1; | |
363 | } | |
364 | if ( tlpLen + f_adjustLen < 3 ) ingressHdr[PEC_PCI__FMT_4DW] = 1; | |
365 | } | |
366 | ||
367 | //Check to see if any of the optional checks are disabled | |
368 | // If they are then the transactin has to pass like a good packet | |
369 | diagCsr = f_env.readCSRdirect( f_env.getCSRaddr( e_CSR_tlu_diag ) ); | |
370 | ||
371 | if( f_cross4K && diagCsr[37] == 1 || | |
372 | f_dwbeSpecified && diagCsr[36] ){ | |
373 | f_env.reserveIngressCredits( ingressHdr ); | |
374 | } | |
375 | ||
376 | if( f_dwbeSpecified ){ | |
377 | f_env.Pod.FNXPCIEEnableTrans.tempSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_MF_vlLastBE0 ); | |
378 | f_env.Pod.FNXPCIEEnableTrans.tempSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_MF_vl1stBE ); | |
379 | f_env.Pod.FNXPCIEEnableTrans.tempSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_MF_vlLastBE1 ); | |
380 | f_env.Pod.FNXPCIEEnableTrans.tempSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_MF_vlNC1stBE ); | |
381 | f_env.Pod.FNXPCIEEnableTrans.tempSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_MF_vlNClastBE ); | |
382 | f_env.Pod.FNXPCIEEnableTrans.tempSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_MF_vlNC1stBE2 ); | |
383 | f_env.Pod.FNXPCIEEnableTrans.tempSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_MF_vlNClastBE2 ); | |
384 | } | |
385 | ||
386 | if( f_mcSpecified && f_TC ){ | |
387 | f_env.Pod.FNXPCIEEnableTrans.tempSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_MF_vlINTxTC ); | |
388 | f_env.Pod.FNXPCIEEnableTrans.tempSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_MF_vlPMTC ); | |
389 | f_env.Pod.FNXPCIEEnableTrans.tempSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_MF_vlERRTC ); | |
390 | } | |
391 | ||
392 | if( f_adjustLen ){ | |
393 | f_env.Pod.FNXPCIEEnableTrans.tempSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_MF_vlSizeTotal ); | |
394 | } | |
395 | //Denali may have an outstanding packet with the same tag because it was an error packet | |
396 | f_env.Pod.FNXPCIEEnableTrans.tempSuppressDenaliErr( PCIE_TL_COR_TLP_USERTAG_2 ); | |
397 | ||
398 | //Give denali extra credits for Writes with big payloads or adjustments | |
399 | // and remove them after | |
400 | if( ( ingressHdr[PEC_PCI__LEN] > 512 || ingressHdr[PEC_PCI__LEN] == 0) && | |
401 | ingressHdr[PEC_PCI__FMT_DATA] && (ingressHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_MEM) ){ | |
402 | tempDenaliData[3:0] = PCIE_FCCTRL_get ; | |
403 | tempDenaliData[7:4] = 4'h0 ; | |
404 | tempDenaliData[11:8] = PCIE_VCID_VC0; | |
405 | tempDenaliData[15:12] = PCIE_FCTYPE_PD; | |
406 | tempDenaliData[19:16] = PCIE_FCID_TX_LIMIT; | |
407 | tempDenaliData[31:20] = 12'h0; | |
408 | //Posted Header - Memory Write | |
409 | ||
410 | f_env.Pod.FNXPCIEEnableTrans.WriteDenaliReg( PCIE_REG_DEN_FC_CTRL,tempDenaliData ); | |
411 | tempDenaliData = f_env.Pod.FNXPCIEEnableTrans.ReadDenaliReg( PCIE_REG_DEN_FC_CTRL ); | |
412 | tempDenaliData[31:20] = tempDenaliData[31:20] + | |
413 | (ingressHdr[PEC_PCI__LEN] == 0 ? 12'h400 : ingressHdr[PEC_PCI__LEN] ); //Extra Data credit | |
414 | tempDenaliData[3:0] = PCIE_FCCTRL_set; | |
415 | f_env.Pod.FNXPCIEEnableTrans.WriteDenaliReg( PCIE_REG_DEN_FC_CTRL,tempDenaliData ); | |
416 | ||
417 | } | |
418 | ||
419 | // Just drive the TLP into the TLU. | |
420 | // No need to worry about credits since | |
421 | // the TLU shouldn't eat any unless the | |
422 | // optional check is disabled | |
423 | f_env.drivePCIE( ingressHdr, ingressData, f_adjustLen, *, *, | |
424 | super.f_abortErrTlp ); | |
425 | ||
426 | f_env.Pod.FNXPCIEEnableTrans.unSuppressDenaliErr( PCIE_TL_COR_TLP_USERTAG_2 ); | |
427 | if( f_dwbeSpecified ){ | |
428 | f_env.Pod.FNXPCIEEnableTrans.unSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_MF_vlLastBE0 ); | |
429 | f_env.Pod.FNXPCIEEnableTrans.unSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_MF_vl1stBE ); | |
430 | f_env.Pod.FNXPCIEEnableTrans.unSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_MF_vlLastBE1 ); | |
431 | f_env.Pod.FNXPCIEEnableTrans.unSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_MF_vlNC1stBE ); | |
432 | f_env.Pod.FNXPCIEEnableTrans.unSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_MF_vlNClastBE ); | |
433 | f_env.Pod.FNXPCIEEnableTrans.unSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_MF_vlNC1stBE2 ); | |
434 | f_env.Pod.FNXPCIEEnableTrans.unSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_MF_vlNClastBE2 ); | |
435 | } | |
436 | ||
437 | if( f_mcSpecified && f_TC ){ | |
438 | f_env.Pod.FNXPCIEEnableTrans.unSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_MF_vlINTxTC ); | |
439 | f_env.Pod.FNXPCIEEnableTrans.unSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_MF_vlPMTC ); | |
440 | f_env.Pod.FNXPCIEEnableTrans.unSuppressDenaliErr( PCIE_TL_NONFATAL_TLP_MF_vlERRTC ); | |
441 | } | |
442 | ||
443 | if( f_cross4K && diagCsr[37] == 1 || | |
444 | f_dwbeSpecified && diagCsr[36] ){ | |
445 | f_env.consumeIngressCredits( ingressHdr ); | |
446 | f_env.expectILU( ingressHdr, ingressData ); | |
447 | } | |
448 | else{ //Return the credits that Denali thinks it has consumed | |
449 | tempDenaliData[3:0] = PCIE_FCCTRL_get ; | |
450 | tempDenaliData[7:4] = 4'h0 ; | |
451 | tempDenaliData[11:8] = PCIE_VCID_VC0; | |
452 | tempDenaliData[15:12] = PCIE_FCTYPE_PH; | |
453 | tempDenaliData[19:16] = PCIE_FCID_TX_CONSUMED; | |
454 | tempDenaliData[31:20] = 12'h0; | |
455 | //Posted Header - Memory Write or Msg | |
456 | if( (ingressHdr[PEC_PCI__FMT_DATA] && (ingressHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_MEM)) | |
457 | || ingressHdr[124] ){ | |
458 | ||
459 | f_env.Pod.FNXPCIEEnableTrans.WriteDenaliReg( PCIE_REG_DEN_FC_CTRL,tempDenaliData ); | |
460 | tempDenaliData = f_env.Pod.FNXPCIEEnableTrans.ReadDenaliReg( PCIE_REG_DEN_FC_CTRL ); | |
461 | tempDenaliData[27:20] = tempDenaliData[27:20] - 1; //Return Header credit | |
462 | tempDenaliData[3:0] = PCIE_FCCTRL_set; | |
463 | f_env.Pod.FNXPCIEEnableTrans.WriteDenaliReg( PCIE_REG_DEN_FC_CTRL,tempDenaliData ); | |
464 | ||
465 | //Return Data credit | |
466 | if( ingressHdr[PEC_PCI__FMT_DATA] ){ | |
467 | ||
468 | tempDenaliData[15:12] = PCIE_FCTYPE_PD; | |
469 | tempDenaliData[3:0] = PCIE_FCCTRL_get ; | |
470 | f_env.Pod.FNXPCIEEnableTrans.WriteDenaliReg( PCIE_REG_DEN_FC_CTRL,tempDenaliData ); | |
471 | tempDenaliData = f_env.Pod.FNXPCIEEnableTrans.ReadDenaliReg( PCIE_REG_DEN_FC_CTRL); | |
472 | //review - Need to add adjustlen | |
473 | tempDenaliData[31:20] = tempDenaliData[31:20] - (ingressHdr[PEC_PCI__LEN] + 3 ) / 4; | |
474 | tempDenaliData[3:0] = PCIE_FCCTRL_set; | |
475 | f_env.Pod.FNXPCIEEnableTrans.WriteDenaliReg( PCIE_REG_DEN_FC_CTRL,tempDenaliData ); | |
476 | } | |
477 | } | |
478 | else{ //Return NonPosted Header credits | |
479 | ||
480 | tempDenaliData[15:12] = PCIE_FCTYPE_NPH; | |
481 | f_env.Pod.FNXPCIEEnableTrans.WriteDenaliReg( PCIE_REG_DEN_FC_CTRL,tempDenaliData ); | |
482 | tempDenaliData = f_env.Pod.FNXPCIEEnableTrans.ReadDenaliReg( PCIE_REG_DEN_FC_CTRL ); | |
483 | tempDenaliData[27:20] = tempDenaliData[27:20] - 1; //Return Header credit | |
484 | tempDenaliData[3:0] = PCIE_FCCTRL_set; | |
485 | f_env.Pod.FNXPCIEEnableTrans.WriteDenaliReg( PCIE_REG_DEN_FC_CTRL,tempDenaliData ); | |
486 | } | |
487 | } | |
488 | ||
489 | //Put back denali extra credits for Writes with big payloads or adjustments | |
490 | if( (ingressHdr[PEC_PCI__LEN] > 512 || ingressHdr[PEC_PCI__LEN] == 0 ) && | |
491 | ingressHdr[PEC_PCI__FMT_DATA] && (ingressHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_MEM) ){ | |
492 | tempDenaliData[3:0] = PCIE_FCCTRL_get ; | |
493 | tempDenaliData[7:4] = 4'h0 ; | |
494 | tempDenaliData[11:8] = PCIE_VCID_VC0; | |
495 | tempDenaliData[15:12] = PCIE_FCTYPE_PD; | |
496 | tempDenaliData[19:16] = PCIE_FCID_TX_LIMIT; | |
497 | tempDenaliData[31:20] = 12'h0; | |
498 | //Posted Header - Memory Write | |
499 | ||
500 | f_env.Pod.FNXPCIEEnableTrans.WriteDenaliReg( PCIE_REG_DEN_FC_CTRL,tempDenaliData ); | |
501 | tempDenaliData = f_env.Pod.FNXPCIEEnableTrans.ReadDenaliReg( PCIE_REG_DEN_FC_CTRL ); | |
502 | tempDenaliData[31:20] = tempDenaliData[31:20] - | |
503 | (ingressHdr[PEC_PCI__LEN] == 0 ? 12'h400 : ingressHdr[PEC_PCI__LEN] ); | |
504 | tempDenaliData[3:0] = PCIE_FCCTRL_set; | |
505 | f_env.Pod.FNXPCIEEnableTrans.WriteDenaliReg( PCIE_REG_DEN_FC_CTRL,tempDenaliData ); | |
506 | ||
507 | } | |
508 | ||
509 | ||
510 | ||
511 | f_env.freeDmaTag( ingressTag ); | |
512 | ||
513 | // Wait for the bad boy(s) to be | |
514 | // processed by the TLU... | |
515 | printf( "MalReq (cycle %0d) Wait for malformed TLP (tag=%h) to enter TLU\n", | |
516 | get_cycle(), ingressTag ); | |
517 | f_env.waitIngressLatency( ingressHdr, (f_adjustLen > 0) ? f_adjustLen : 0 ); | |
518 | ||
519 | // If the context wants, put the bad-boy | |
520 | // header (and the cause) into a mailbox | |
521 | if ( f_errQueue != 0 && f_adjustLen >= 0 ) | |
522 | { | |
523 | // Any malformed request | |
524 | // might generate a receiver overflow. | |
525 | mailbox_put( f_errQueue, e_ERR_none ); | |
526 | mailbox_put( f_errQueue, 2 ); | |
527 | mailbox_put( f_errQueue, e_ERR_ue_mfp ); | |
528 | mailbox_put( f_errQueue, ingressHdr ); | |
529 | mailbox_put( f_errQueue, e_ERR_ue_rof ); | |
530 | mailbox_put( f_errQueue, 128'bx0 ); | |
531 | } | |
532 | ||
533 | // If the length adjustment was negative | |
534 | // then we can't expect a valid header | |
535 | // in the log register, and we might get | |
536 | // a second 'mfp' error from the TLU. | |
537 | else if ( f_errQueue != 0 && f_adjustLen < 0 ) | |
538 | { | |
539 | mailbox_put( f_errQueue, e_ERR_none ); | |
540 | mailbox_put( f_errQueue, 3 ); | |
541 | mailbox_put( f_errQueue, e_ERR_ue_rof ); | |
542 | mailbox_put( f_errQueue, 128'bx0 ); | |
543 | mailbox_put( f_errQueue, e_ERR_ue_mfp ); | |
544 | mailbox_put( f_errQueue, 128'bx ); // Don't check the logged data | |
545 | mailbox_put( f_errQueue, e_ERR_ue_mfp ); | |
546 | mailbox_put( f_errQueue, 128'bx0 ); // Clear all logged-error bits | |
547 | } | |
548 | ||
549 | printf( "MalReq (cycle %0d) Done (tag=%h)\n", get_cycle(), ingressTag ); | |
550 | } /* end Execute */ | |
551 | } /* end MalReqPEUStr */ | |
552 |