Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / env / fnx / vlib / DMUXtr / vera / DMUXtr.vr
CommitLineData
86530b38
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: DMUXtr.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#include "DMUXtr.vri"
36#include "report_info.vrh"
37#include "cReport.vrh"
38
39class DMUXtr
40 {
41 local po_DMUingress ingressPort;
42 local po_DMUegress egressPort;
43 po_DMUmisc miscPort;
44 ReportClass Report;
45
46 local integer mutex; // A general-purpose mutex
47 local integer egressHdrQueue; // Mailbox: TLPs to send to the ILU
48 local integer egressQueue; // Mailbox: Parms for the hdr above
49 local integer egressEventQueue; // Mailbox: "send" completion events
50 local integer egressRelQueue; // External mailbox: release records
51 local integer ingressHdrQueue; // Mailbox: Expected TLPs from the ILU
52 local integer ingressQueue; // Mailbox: Parms for the hdr above
53 local integer ingressEventQueue; // Mailbox: "recv" completion events
54 local integer ingressDataQueue; // Mailbox: Data to be pulled from ILU
55 local integer ingressDataEventQueue; // Mailbox: Data to be pulled from ILU
56 local bit [7:0] ingressDataAddr; // Next IDB row to pull
57 local bit [127:0] dataOutMemory[256]; // Representing the DOU memory
58 local bit [1023:0] dataOutMemoryErr; // Should a parity error be injected?
59 local integer avgIngressCredits; // The target # of "ingressCredits"
60 local integer ingressCredits; // # of available ingress enq credits
61 local integer egressCredits; // # of available egress enq credits
62 local integer dequeuePending; // # of pending ingress credits to deq
63 local bit dequeueEnable; // Should we return ingress credits?
64 local integer dequeueMinDelay; // Min # of cycles between dequeues
65 local integer dequeueMaxDelay; // Max # of cycles between dequeues
66
67 local integer cplQueue; // A mailbox for unexpected bad cpl'ns
68
69 local bit ingressHdrLookAhead; // Has 'ingressHdr' pulled a header?
70
71 local bit disableUnusedParityCheck; // Should unused parity bits be ignored?
72
73 local bit debugOK; // Should debug messages be printed?
74
75 local bit reset_pending;
76
77
78 // User interface...
79 task new( po_DMUingress a_ingressPort, po_DMUegress a_egressPort, po_DMUmisc a_miscPort , ReportClass _Report );
80 task enableXtr();
81 task setRelMailbox( integer RelMailbox );
82 task setCplMailbox( integer CplMailbox );
83 task send( bit[PEC_PCI__HDR] tlpHdr,
84 bit[31:0] payload,
85 bit[7:0] douAddr );
86 task recv( bit[PEC_PCI__HDR] tlpHdr,
87 bit[31:0] payload,
88 (bit optional=0) );
89 task setIngressDequeueDelay( integer MinDelay, integer MaxDelay );
90 task disableIngressDequeue();
91 task enableIngressDequeue();
92 task clear( bit TriggerExpectEvents );
93 task reset();
94 task ignoreUnusedParity();
95
96 task setAvgIngressCreditsAvailable( integer Credits );
97 function integer ingressCreditsAvailable();
98 function integer egressCreditsAvailable();
99
100
101 // Threads manning the ILU interfaces...
102 local task ingressHdr();
103 local task ingressData(); // includes submitting release recds
104 local task ingressDeq();
105 local task egressHdr();
106 local task egressData();
107 local task egressRel();
108
109 // Some service routines...
110 local function
111 bit checkPecRecd( bit[PEC__RECD] pecRecd, bit[PEC_PCI__HDR] tlpHdr );
112 local task reportPecErr( bit[PEC__RECD] pecRecd, bit[PEC_PCI__HDR] tlpHdr );
113 local task putCplQueue( bit[PEC__RECD] pecRecd );
114
115 local task sendPecRecd( bit[PEC_PCI__HDR] tlpHdr, bit[7:0] douAddr );
116 local task fillDataOut( bit[7:0] douAddr,
117 integer dwCount,
118 bit[7:0] payload,
119 integer gasDWs,
120 bit cplData );
121 local task injectParityErr( bit[7:0] douAddr,
122 integer gasDWs,
123 bit[7:0] errMask );
124 local task fillCplData( bit[7:0] douAddr );
125 local task enqueueIngressData( bit[8:0] payload,
126 integer dwCount,
127 bit posted );
128 local task dequeueIngressData( var bit[7:0] payload,
129 var bit payloadErr,
130 var integer dwCount,
131 var bit posted );
132
133 }
134
135#define _WAIT_A_CYCLE @1 egressPort.$enq = void
136#define _REPORT_ERROR(msg) Report.report(RTYP_TEST_ERROR,"DMUXtr (cycle %d) %s\n", get_cycle(), msg)
137//#define _REPORT_ERROR(msg) error("DMUXtr (cycle %d) %s\n", get_cycle(), msg)
138#define _ERROR_INFO(msg) printf("DMUXtr (cycle %d) %s\n", get_cycle(), msg)
139#define _INFO_MSG(msg) printf("DMUXtr (cycle %d) %s\n", get_cycle(), msg)
140#define _DEBUG_MSG(msg) if ( debugOK ) _INFO_MSG(msg)
141#define _ACQUIRE_MUTEX void = semaphore_get(WAIT,mutex,1)
142#define _RELEASE_MUTEX semaphore_put(mutex,1)
143
144/*
145* new - Allocate a DMU transactor
146*/
147task DMUXtr::new( po_DMUingress a_ingressPort, po_DMUegress a_egressPort, po_DMUmisc a_miscPort, ReportClass _Report )
148 {
149 bit [7:0] i = 0;
150 ingressPort = a_ingressPort;
151 egressPort = a_egressPort;
152 miscPort = a_miscPort;
153 Report = _Report;
154
155 //Come up in reset
156#ifndef N2_FC
157 miscPort.$pwrOnRstN <= 1'b0;
158 miscPort.$resetN <= 1'b0;
159
160 egressPort.$douvalid <= 1'b0;
161 egressPort.$douerr <= 1'b0;
162#endif
163
164 // Everything is allocated by "enableXtr"
165 egressRelQueue = 0;
166
167 dequeueMinDelay = 0;
168 dequeueMaxDelay = 5;
169 dequeueEnable = 1;
170
171 avgIngressCredits = 1;
172
173 // "setCplQueue" tells us about a mailbox to put unexpected unsuccessful cplns
174 cplQueue = 0;
175
176 dataOutMemoryErr = 1024'b0;
177
178 disableUnusedParityCheck = 0;
179
180 reset_pending = 0;
181
182// review
183// for( i=0; i<256; i++ ){
184// dataOutMemory[i] = {96'hdeadbeefdeadbeefdeadbeefdead00,i};
185// }
186// debugOK = get_plus_arg(CHECK,"DMUDUMP");
187
188 debugOK = 0;
189 if (Report.get_global_print_threshold() < RPRT_DEBUG_1) {
190 debugOK = 1;
191 }
192 } /* end new */
193
194/*
195* setRelMailbox - Establish a mailbox for sending ILU release records
196*
197* Parameters:
198* RelMailbox - The mailbox to receive ILU release records (egress)
199*
200* This task is called by the test environment to allow it to receive
201* information on PIO tags and DOU blocks released by the ILU. Each mailbox
202* entry is nine-bits, with the high-order bit indicating a released DOU block
203* (followed by the starting DOU address of the released block).
204*/
205task DMUXtr::setRelMailbox( integer RelMailbox )
206 {
207 egressRelQueue = RelMailbox;
208 } /* end setRelMailbox */
209
210/*
211* setCplMailbox - Establish a mailbox for sending unexpected unsuccessful cplns
212*
213* Parameters:
214* CplMailbox - The mailbox to receive those bad-boy headers
215*
216* This task is called by the test environment to allow it to receive
217* the headers for completion-TLPs which are unexpected (i.e. not specified
218* by a "recv" call) and unsuccessful (i.e. PEC_PCI__CPL_STATUS is non-zero).
219* If this mailbox is not set, then these unexpected headers (like any other
220* unexpected TLP) will be recorded as an error.
221*/
222task DMUXtr::setCplMailbox( integer CplMailbox )
223 {
224 cplQueue = CplMailbox;
225 } /* end setCplMailbox */
226
227/*
228* enableXtr - Initialize all local variables and start manning the ports!
229*
230* Parameters: None
231*/
232task DMUXtr::enableXtr()
233 {
234 if ( reset_pending )
235 {
236 reset_pending = 0;
237 return;
238 }
239 // The ingress and egress pipelines
240 // both start with credits.
241 ingressCredits = PEC_ILU_INGRESS_CREDITS; //6 credits
242 egressCredits = PEC_ILU_EGRESS_CREDITS; //4 credits
243 dequeuePending = 0;
244
245 // A mutex for local critical sections
246 mutex = alloc(SEMAPHORE,0,1,1);
247
248 // The ingress and egress pipelines
249 // each have three queues, one holding
250 // the TLP header which is expected or
251 // is to be sent, and another holding
252 // "other" data given to send/recv, and
253 // a final queue holding events which
254 // signal completion.
255 ingressQueue = alloc(MAILBOX,0,1);
256 ingressHdrQueue = alloc(MAILBOX,0,1);
257 ingressEventQueue = alloc(MAILBOX,0,1);
258 egressQueue = alloc(MAILBOX,0,1);
259 egressHdrQueue = alloc(MAILBOX,0,1);
260 egressEventQueue = alloc(MAILBOX,0,1);
261
262 ingressHdrLookAhead = 1'b0;
263
264 // A separate queue holds expected
265 // data to be pulled by an "ingressData"
266 // thread, and events to trigger.
267 ingressDataQueue = alloc(MAILBOX,0,1);
268 ingressDataEventQueue = alloc(MAILBOX,0,1);
269
270 // Start threads for ingress/egress
271 // TLP headers and payload.
272 // The "egressHdr" thread takes care of
273 // monitoring the egress "deq" signal,
274 // while a separate thread has the job
275 // of asserting it on the ingress side.
276
277 fork
278 ingressHdr();
279 ingressData();
280 ingressDeq();
281 egressHdr();
282 egressData();
283 egressRel();
284 join none
285 } /* end enableXtr */
286
287/*
288* send - Add a TLP to the egress pipeline
289*
290* Parameters:
291* tlpHdr - The TLP header (PCI-Express format) to be sent
292* payload - The payload specification
293* douAddr - The starting data-out address for payload
294*/
295task DMUXtr::send( bit[PEC_PCI__HDR] tlpHdr,
296 bit[31:0] payload,
297 bit[7:0] douAddr )
298 {
299 event allDone;
300 bit[7:0] payloadByte;
301 bit[7:0] poisonedPayload;
302 bit fillPayload;
303 bit errPayload;
304 bit[7:0] errMask;
305
306 payloadByte = payload[7:0];
307 poisonedPayload = payload[15:8];
308 fillPayload = payload[16];
309 errPayload = payload[17];
310 errMask = payload[25:18];
311
312 // Add a cleared event to the egress
313 // event queue.
314 trigger( OFF, allDone );
315 mailbox_put( egressEventQueue, allDone );
316
317 // Add the header to the ingress
318 // header queue, and put the data
319 // specification in the control queue.
320 // The data-out memory is initialized
321 // just before the header is sent.
322 _DEBUG_MSG( psprintf( "\nTLPHDR (DMUXtr:send):\tFMT=%x TYPE=%x TC=%x ATTR=%x LEN=%x REQID=%x TAG=%x ADDR=%x LAST_DWBE=%x FIRST_DWBE=%x\n",
323 tlpHdr[PEC__FMT],
324 tlpHdr[PEC__TYPE],
325 tlpHdr[PEC__TC],
326 tlpHdr[PEC__ATTR],
327 tlpHdr[PEC__LEN],
328 tlpHdr[PEC__REQ_ID],
329 tlpHdr[PEC__TLP_TAG],
330 tlpHdr[PEC__ADDR32],
331 tlpHdr[PEC__LAST_DWBE],
332 tlpHdr[PEC__FIRST_DWBE] )
333 );
334
335 mailbox_put( egressHdrQueue, tlpHdr );
336 mailbox_put( egressQueue, {errMask,errPayload,poisonedPayload,payloadByte,douAddr} );
337
338 // Wait for the TLP to be sent.
339 sync( ANY, allDone );
340 } /* end send */
341
342/*
343* recv - Add a TLP to the ingress pipeline expect-queue
344*
345* Parameters:
346* tlpHdr - The expected TLP header
347* payload - The payload specification
348*/
349task DMUXtr::recv( bit[PEC_PCI__HDR] tlpHdr,
350 bit[31:0] payload,
351 (bit optional=0) )
352 {
353 event allDone;
354 bit[7:0] payloadByte;
355 bit payloadErr;
356
357 _DEBUG_MSG( psprintf("DMUXtr::recv time = %d, DMUXtr.recv(tlpHdr=128'h%0h, payload=32'h%0h\n",get_time(LO), tlpHdr,payload));
358
359 payloadByte = payload[7:0];
360 payloadErr = payload[14]; // The "erroneous" bit from the env't
361
362 // Add a cleared event to the ingress
363 // event queue.
364 trigger( OFF, allDone );
365 mailbox_put( ingressEventQueue, allDone );
366
367 // Add the header and payload-spec
368 // to the appropriate ingress queues.
369 mailbox_put( ingressHdrQueue, tlpHdr );
370 mailbox_put( ingressQueue, {optional,payloadErr,payloadByte} );
371
372 // Wait for the TLP to arrive.
373 sync( ANY, allDone );
374 } /* end recv */
375
376/*
377* setAvgIngressCreditsAvailable - Set the number of "enqueue" credits that
378* the ILU has available (on average)
379*
380* Parameters:
381* Credits - The target average value of "ingressCreditsAvailable" (below)
382*
383* NOTE: If "Credits" is out of range (i.e. negative), then the transactor
384* picks an average (target) value, and changes it periodically.
385*/
386task DMUXtr::setAvgIngressCreditsAvailable( integer Credits )
387 {
388 if ( Credits < 0 || Credits > PEC_ILU_INGRESS_CREDITS )
389 avgIngressCredits = 1;
390 else
391 avgIngressCredits = Credits;
392 } /* end setAvgIngressCreditsAvailable */
393
394/*
395* ingressCreditsAvailable - How many enqueue credits does the ILU have?
396*/
397function integer DMUXtr::ingressCreditsAvailable()
398 {
399 ingressCreditsAvailable = ingressCredits;
400 }
401
402/*
403* egressCreditsAvailable - How many enqueue credits does the DMU have?
404*/
405function integer DMUXtr::egressCreditsAvailable()
406 {
407 egressCreditsAvailable = egressCredits;
408 }
409
410/*
411* setIngressDequeueDelay - Set the minimum and maximum number of cycles before
412* returning an ingress header credit to the ILU.
413*
414* Parameters:
415* MinDelay - The minimum delay from one "dequeue" to the next
416* MaxDelay - The maximum such delay
417*/
418task DMUXtr::setIngressDequeueDelay( integer MinDelay, integer MaxDelay )
419 {
420 if ( MinDelay >= 0 && MaxDelay >= MinDelay )
421 {
422 dequeueMinDelay = MinDelay;
423 dequeueMaxDelay = MaxDelay;
424 }
425 }
426
427/*
428* disableIngressDequeue - Stop returning ingress header credits to the ILU.
429*/
430task DMUXtr::disableIngressDequeue()
431 {
432 dequeueEnable = 0;
433 } /* end disableIngressDequeue */
434
435/*
436* enableIngressDequeue - Resume returning ingress header credits to the ILU
437*/
438task DMUXtr::enableIngressDequeue()
439 {
440 dequeueEnable = 1;
441 } /* end enableIngressDequeue */
442
443/*
444* clear - Clear ingress expected TLPs
445*/
446task DMUXtr::clear( bit TriggerExpectEvents )
447 {
448 bit [7:0] payload;
449 bit [PEC_PCI__HDR] tlpHdr;
450 bit [24:0] tlpSpec;
451 event allDone = null;
452
453 while( mailbox_get(NO_WAIT,ingressHdrQueue) > 0 )
454 {
455 void = mailbox_get( NO_WAIT, ingressHdrQueue, tlpHdr );
456 void = mailbox_get( NO_WAIT, ingressQueue, payload );
457 void = mailbox_get( NO_WAIT, ingressEventQueue, allDone );
458 if ( allDone != null && TriggerExpectEvents ) trigger( ONE_SHOT, allDone );
459 }
460 while( mailbox_get(NO_WAIT, ingressDataQueue) > 0 )
461 void = mailbox_get( NO_WAIT, ingressDataQueue, tlpHdr );
462 ingressHdrLookAhead = 0;
463
464 }
465
466/*
467* reset - Put everything(?) back to where it was when we started
468*/
469task DMUXtr::reset()
470 {
471 bit [7:0] payload;
472 bit [PEC_PCI__HDR] tlpHdr;
473 bit [24:0] tlpSpec;
474 event allDone = null;
475
476#ifndef N2_FC
477 ingressPort.$addr <= 8'b0;
478#endif
479 dataOutMemoryErr = 1024'b0;
480 ingressCredits = PEC_ILU_INGRESS_CREDITS;
481 egressCredits = PEC_ILU_EGRESS_CREDITS;
482 dequeuePending = 0;
483 ingressDataAddr = 8'b0;
484 while( mailbox_get(NO_WAIT,ingressHdrQueue) > 0 )
485 {
486 void = mailbox_get( NO_WAIT, ingressHdrQueue, tlpHdr );
487 void = mailbox_get( NO_WAIT, ingressQueue, payload );
488 void = mailbox_get( NO_WAIT, ingressEventQueue, allDone );
489 }
490 while( mailbox_get(NO_WAIT, ingressDataQueue) > 0 )
491 void = mailbox_get( NO_WAIT, ingressDataQueue, tlpHdr );
492 ingressHdrLookAhead = 0;
493 while( mailbox_get( NO_WAIT, egressHdrQueue ) > 0 )
494 {
495 void = mailbox_get( NO_WAIT, egressHdrQueue, tlpHdr );
496 void = mailbox_get( NO_WAIT, egressQueue, tlpSpec );
497 void = mailbox_get( NO_WAIT, egressEventQueue, allDone );
498 }
499
500 reset_pending = 1;
501 } /* end reset */
502
503/*
504* ignoreUnusedParity - Don't report an error if parity from the IDB is not
505* correct for DWs which are not part of the original TLP.
506*
507* Parameters: None
508*/
509task DMUXtr::ignoreUnusedParity()
510 {
511 disableUnusedParityCheck = 1;
512 } /* end ignoreUnusedParity */
513
514/*
515* ingressHdr - Monitor the ILU's ingress PEC port and make sure that
516* everything that comes out is expected
517*/
518task DMUXtr::ingressHdr()
519 {
520 bit [9:0] stuff;
521 bit optional;
522 bit [8:0] payload;
523 bit [PEC_PCI__HDR] tlpHdr;
524 event allDone = null;
525 string tmp;
526
527#ifndef N2_FC
528 ingressHdrLookAhead = 0;
529 while( 1 )
530 {
531 _WAIT_A_CYCLE;
532 while( reset_pending ) _WAIT_A_CYCLE;
533
534 // If the ILU is presenting a PEC recd,
535 if ( ingressPort.$enq )
536 {
537 // ...make sure that it has a credit
538 // to do so...
539 if ( ingressCredits == 0 )
540 {
541 _REPORT_ERROR( "Ingress PEC record enqueued with no credits available");
542 }
543
544 // ...and that a record is expected...
545 else if ( !ingressHdrLookAhead && mailbox_get(NO_WAIT,ingressQueue) == 0 )
546 {
547 if ( ingressPort.$recd[PEC__TYPE] == PEC_PCI__TYPE_CPL
548 && ingressPort.$recd[PEC__CPL_STATUS] != 0
549 && cplQueue != 0 )
550 {
551 putCplQueue( ingressPort.$recd );
552 }
553 else
554 {
555 tmp = { "Ingress PEC record enqueued when none expected: ",
556 psprintf("PEC__TYPE='d%0d, CPL_STATUS='d%0d, cplQueue=%0d",
557 ingressPort.$recd[PEC__TYPE],
558 ingressPort.$recd[PEC__CPL_STATUS],
559 cplQueue) };
560 _REPORT_ERROR( tmp );
561 }
562 }
563
564 // ...and then check the presented PEC
565 // record against the expected TLP
566 // header. Any payload is checked by
567 // the "ingressData" thread.
568 else
569 {
570 if ( !ingressHdrLookAhead )
571 {
572 void = mailbox_get( NO_WAIT, ingressHdrQueue, tlpHdr );
573 void = mailbox_get( NO_WAIT, ingressQueue, stuff );
574 void = mailbox_get( NO_WAIT, ingressEventQueue, allDone );
575 optional = stuff[9];
576 payload = stuff[8:0];
577 }
578 ingressHdrLookAhead = 0;
579
580 // Skip past optional TLPs which
581 // don't match what we've got.
582 while( optional
583 && mailbox_get(NO_WAIT,ingressQueue) > 0
584 && checkPecRecd( ingressPort.$recd, tlpHdr ) )
585 {
586 trigger( ON, allDone );
587 void = mailbox_get( NO_WAIT, ingressHdrQueue, tlpHdr );
588 void = mailbox_get( NO_WAIT, ingressQueue, stuff );
589 void = mailbox_get( NO_WAIT, ingressEventQueue, allDone );
590 optional = stuff[9];
591 payload = stuff[8:0];
592 }
593
594 // If the PEC record doesn't match...
595 if ( checkPecRecd( ingressPort.$recd, tlpHdr ) )
596 {
597 // ...then either put an unsuccessful
598 // completion into the "cplQueue"...
599 ingressHdrLookAhead = 1;
600 if ( ingressPort.$recd[PEC__TYPE] == PEC_PCI__TYPE_CPL
601 && ingressPort.$recd[PEC__CPL_STATUS] != 0
602 && cplQueue != 0 )
603 {
604 putCplQueue( ingressPort.$recd );
605 }
606
607 // ...or complain mightily.
608 else
609 {
610 reportPecErr( ingressPort.$recd, tlpHdr );
611 }
612 }
613
614 // And if the (matching) TLP has data
615 // then tell the "ingressData" thread
616 // to check the payload's validity.
617 else if ( ingressPort.$recd[PEC__FMT_DATA] )
618 {
619 mailbox_put( ingressDataEventQueue, allDone );
620 enqueueIngressData( payload,
621 ingressPort.$recd[PEC__LEN],
622 ingressPort.$recd[PEC__TYPE]!=PEC_PCI__TYPE_CPL );
623 }
624
625 // Otherwise, just signal whoever
626 // expected the TLP that we got it!
627 else
628 {
629 trigger( ON, allDone );
630 }
631 }
632
633 // The ILU has consumed a credit.
634 // The "ingressDeq" thread will take
635 // care of returning the credit.
636 _ACQUIRE_MUTEX;
637 ingressCredits = ingressCredits - 1;
638 dequeuePending = dequeuePending + 1;
639 if ( ingressCredits == 0 ) _DEBUG_MSG( "Ingress credits exhausted" );
640 _RELEASE_MUTEX;
641 } /* end "if ingressPort.$enq is asserted..." */
642 }
643#endif
644 } /* end ingressHdr */
645
646/*
647* putCplQueue - Add a TLP (a CPL header) to the "cplQueue"
648*
649* Parameters:
650* pecRecd - The PEC record denoting the TLP to be added to the "cplQueue"
651*/
652task DMUXtr::putCplQueue( bit[PEC__RECD] pecRecd )
653 {
654 bit [127:0] pciHdr;
655
656 pciHdr = 128'b0;
657 pciHdr[PEC_PCI__FMT] = pecRecd[PEC__FMT];
658 pciHdr[PEC_PCI__TYPE] = pecRecd[PEC__TYPE];
659 pciHdr[PEC_PCI__LEN] = pecRecd[PEC__LEN];
660 pciHdr[PEC_PCI__TC] = pecRecd[PEC__TC];
661 pciHdr[PEC_PCI__ATTR] = pecRecd[PEC__ATTR];
662 pciHdr[PEC_PCI__CPL_ID] = pecRecd[PEC__CPL_ID];
663 pciHdr[PEC_PCI__CPL_STATUS] = pecRecd[PEC__CPL_STATUS];
664 pciHdr[PEC_PCI__CPL_REQ_ID] = pecRecd[PEC__CPL_REQ_ID];
665 pciHdr[PEC_PCI__CPL_TAG] = pecRecd[PEC__CPL_TAG];
666 pciHdr[PEC_PCI__BCM] = pecRecd[PEC__BCM];
667 pciHdr[PEC_PCI__LOWADDR] = pecRecd[PEC__LOWADDR];
668
669 mailbox_put( cplQueue, pciHdr );
670
671 } /* end putCplQueue */
672
673/*
674* ingressData - Pull data from the IDB and make sure that it matches the
675* expected result.
676*
677* NOTE: The current implementation assumes a one-cycle IDB delay
678*/
679task DMUXtr::ingressData()
680 {
681 event allDone = null;
682 integer dwCount;
683 bit [7:0] payload;
684 bit payloadErr;
685 bit posted;
686 bit [7:0] nextAddr;
687 integer byteCount;
688 integer rowCount;
689 integer i;
690 bit [127:0] dataRow;
691 string errMsg;
692 bit payloadErrFound;
693 bit [3:0] goodParity;
694
695#ifndef N2_FC
696 ingressDataAddr = 8'b0;
697 ingressPort.$addr = 8'b0;
698 ingressPort.$relrcdenq = 1'b0;
699 _WAIT_A_CYCLE;
700
701 nextAddr = 8'b1;
702 while( 1 )
703 {
704 while( reset_pending ) { printf( "Waiting for reset...\n" ); _WAIT_A_CYCLE;}
705
706 // Wait for some data to pull...
707 dequeueIngressData( payload, payloadErr, dwCount, posted );
708
709 // Make sure that the payload is
710 // what we expect.
711 rowCount = (dwCount+3) / 4;
712 byteCount = dwCount * 4;
713 // - put a randomized delay here since data doesn't have to come back right away
714 //FIRE MAS pg. 227
715
716 // We've got the IDB row of interest
717 // (or more correctly its address)
718 // already in the pipeline. Go ahead
719 // and get the next row.
720 nextAddr = ingressDataAddr + 1;
721 ingressPort.$addr = nextAddr;
722 nextAddr = nextAddr + 1;
723 rowCount = rowCount - 1;
724 _WAIT_A_CYCLE;
725
726 payloadErrFound = 0;
727 while( byteCount > 0 && !reset_pending)
728 {
729 dataRow = ingressPort.$data;
730
731 goodParity = ~{ ^dataRow[127:96], ^dataRow[95:64],
732 ^dataRow[63:32], ^dataRow[31:0] };
733 if ( ingressPort.$par != goodParity && disableUnusedParityCheck )
734 {
735 if ( byteCount <= 12 ) goodParity[3] = ingressPort.$par[3];
736 if ( byteCount <= 8 ) goodParity[2] = ingressPort.$par[2];
737 if ( byteCount <= 4 ) goodParity[1] = ingressPort.$par[1];
738 }
739 if ( ingressPort.$par != goodParity )
740 {
741 payloadErrFound = 1;
742 if ( !payloadErr )
743 _REPORT_ERROR( "Incorrect data parity from IDB" );
744 }
745
746 for ( i=0; i<16 && byteCount>0; i++ )
747 {
748 if ( dataRow[127:120] != payload )
749 {
750 _REPORT_ERROR( "Incorrect payload from IDB" );
751 sprintf( errMsg, "Expect: %x Actual: %x", payload, dataRow[127:120]);
752 _ERROR_INFO( errMsg );
753 return;
754 }
755 dataRow = {dataRow[119:0],8'b0};
756 byteCount = byteCount - 1;
757 payload = payload + 1;
758 }
759
760 // Tell the ILU that we're all done
761 // with this IDB row.
762 if ( !reset_pending )
763 {
764 ingressPort.$relrcdenq = 1'b1;
765 ingressPort.$relrcd = {posted,ingressDataAddr};
766 ingressDataAddr = ingressDataAddr + 1;
767 }
768
769 // We're done with this row... get the
770 // next one.
771 if ( rowCount > 0 )
772 {
773 ingressPort.$addr = nextAddr;
774 nextAddr = nextAddr + 1;
775 rowCount = rowCount - 1;
776 }
777 _WAIT_A_CYCLE;
778 } /* end "while there's payload to check..." */
779
780 if ( payloadErr && !payloadErrFound )
781 {
782 _REPORT_ERROR( "No data parity error detected when one is expected" );
783 }
784
785 // Tell whoever that we've finished
786 // looking at the payload.
787 void = mailbox_get( NO_WAIT, ingressDataEventQueue, allDone );
788 if ( !reset_pending ) trigger( ON, allDone );
789
790 // Stop sending release records.
791 ingressPort.$relrcdenq = 1'b0;
792 }
793#endif
794 } /* end ingressData */
795
796/*
797* ingressDeq - Return PEC record credits to the ILU
798*/
799task DMUXtr::ingressDeq()
800 {
801 integer deqDelay;
802
803#ifndef N2_FC
804 deqDelay = -1;
805
806 //Initialize rcd_deq signal
807 ingressPort.$deq = 1'b0;
808
809 while( 1 )
810 {
811 _WAIT_A_CYCLE;
812 // If there's a dequeue to process and
813 // if we don't have a "delay" value,
814 // then now's a good time to get one.
815 // Use the max delay if the ILU has
816 // far too many credits, and the min
817 // if it's underfed.
818 if ( dequeuePending > 0 && deqDelay < 0 )
819 {
820 if ( ingressCredits > avgIngressCredits + 2 )
821 deqDelay = -1;
822 else if ( ingressCredits > avgIngressCredits )
823 deqDelay = dequeueMaxDelay;
824 else if ( ingressCredits < avgIngressCredits - 1 )
825 deqDelay = dequeueMinDelay;
826 else if ( dequeueMinDelay < dequeueMaxDelay )
827 deqDelay = dequeueMinDelay
828 + (urandom() % (dequeueMaxDelay-dequeueMinDelay+1) );// set to range min,max
829 else
830 deqDelay = dequeueMinDelay;
831 }
832
833 // If there are credits to be returned
834 // and if we've waited long enough...
835 if ( dequeuePending > 0 && deqDelay == 0 && dequeueEnable )
836 {
837 // ...assert the "dequeue" signal.
838 _ACQUIRE_MUTEX;
839 dequeuePending = dequeuePending - 1;
840 if ( dequeuePending == 0 ) deqDelay = -1;
841 ingressCredits = ingressCredits + 1;
842 _RELEASE_MUTEX;
843 ingressPort.$deq = 1'b1;
844 }
845 // Otherwise, no credit!
846 else
847 {
848 ingressPort.$deq = 1'b0;
849 if ( deqDelay > 0 ) deqDelay = deqDelay - 1;
850 }
851 }
852#endif
853 } /* end ingressDeq */
854
855/*
856* egressHdr - Supply PEC records from the "egressQueue" to the ILU
857*
858* Parameters: None
859*/
860task DMUXtr::egressHdr()
861 {
862 integer enqDelay;
863 integer validDelay;
864 bit [PEC_PCI__HDR] tlpHdr;
865 bit [63:0] tlpAddr;
866 bit [32:0] tlpSpec;
867 bit [7:0] douAddr;
868 bit [7:0] payload;
869 bit [8:0] poison;
870 integer gasDWs;
871 bit sendCplD;
872 integer douBlkCount;
873 bit [31:0] pendingDouBlks;
874 bit [31:0] pendingErrBlks;
875 event allDone = null;
876 integer i;
877 bit ptyErr; // Inject a parity error in the firstDW?
878 bit [7:0] ptyErrMask;
879
880#ifndef N2_FC
881 enqDelay = 0; /*???*/
882 validDelay = 0; /*???*/
883 pendingDouBlks = 32'b0;
884 pendingErrBlks = 32'b0;
885 while( 1 )
886 {
887 _WAIT_A_CYCLE;
888 while( reset_pending ) _WAIT_A_CYCLE;
889
890 // If the ILU has raised the "deq"
891 // signal, then we have a credit!
892 if ( egressPort.$deq )
893 {
894 if ( egressCredits == PEC_ILU_EGRESS_CREDITS )
895 _REPORT_ERROR( "ILU raises 'deq' when no credit is expected" );
896 else
897 egressCredits = egressCredits + 1;
898 }
899
900 // If we've got a TLP to send and if
901 // we've got a credit and if we've
902 // waited long enough, then just do it!
903 sendCplD = 0;
904 if ( mailbox_get( NO_WAIT, egressQueue ) > 0
905 && egressCredits > 0
906 && enqDelay == 0 )
907 {
908 egressCredits = egressCredits - 1;
909 void = mailbox_get( NO_WAIT, egressHdrQueue, tlpHdr );
910 void = mailbox_get( NO_WAIT, egressQueue, tlpSpec );
911 void = mailbox_get( NO_WAIT, egressEventQueue, allDone );
912 ptyErr = tlpSpec[24];
913 ptyErrMask = tlpSpec[32:25];
914 poison = { 1'b0, tlpSpec[23:16] };
915 payload = tlpSpec[15:8];
916 douAddr = tlpSpec[7:0];
917 if ( tlpHdr[PEC_PCI__FMT_DATA] )
918 {
919 if ( tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_CPL )
920 {
921 tlpAddr = tlpHdr[PEC_PCI__LOWADDR];
922 gasDWs = tlpAddr[5:2];
923 egressPort.$douaddr <= douAddr[6:2];
924 sendCplD = 1;
925 }
926 else
927 {
928 tlpAddr = tlpHdr[PEC_PCI__FMT_4DW] ? tlpHdr[PEC_PCI__ADDR]
929 : tlpHdr[PEC_PCI__ADDR32];
930 gasDWs = tlpAddr[3:2];
931 poison = 0;
932 }
933 fillDataOut( douAddr, tlpHdr[PEC_PCI__LEN], payload, gasDWs, sendCplD );
934 if ( ptyErr ){
935 _DEBUG_MSG( psprintf("DMUXtr.egressHdr ptyErr is set calling injectParityErr tag=%0h douAddr=%0h payload=%0h gasDWs=%0h ",
936tlpHdr[PEC__TLP_TAG],douAddr,payload,gasDWs) );
937
938 injectParityErr( douAddr, gasDWs, ptyErrMask );
939 }
940 }
941 sendPecRecd( tlpHdr, douAddr );
942 egressPort.$enq <= 1'b1;
943 trigger( ON, allDone );
944 }
945
946 else
947 {
948 egressPort.$enq <= 1'b0;
949 if ( enqDelay > 0 ) enqDelay = enqDelay - 1;
950 }
951
952 // If we sent a DMA completion with data
953 // then tell the ILU that the block is
954 // valid and record the other blocks
955 // which must be made valid before the
956 // ILU can present the TLP to the TLU.
957 if ( sendCplD )
958 {
959 egressPort.$douvalid <= 1'b1;
960 egressPort.$douerr <= poison[0];
961 douBlkCount = (gasDWs + tlpHdr[PEC_PCI__LEN] + 15) / 16;
962 for ( i=1; i<douBlkCount; i++ )
963 {
964 pendingDouBlks[ (douAddr[6:2]+i) % 32 ] = 1'b1;
965 pendingErrBlks[ (douAddr[6:2]+i) % 32 ] = poison[i];
966 }
967 }
968
969 // Otherwise, if there are DOU blocks
970 // to be made valid, then pick one.
971 else if ( validDelay==0 && pendingDouBlks != 32'b0 && (urandom() % 4)==0 )
972 {
973 i = urandom() % 32;
974 while( pendingDouBlks[i] == 1'b0 ) i = (i+11)%32;
975 pendingDouBlks[i] = 1'b0;
976 egressPort.$douaddr <= i;
977 egressPort.$douvalid <= 1'b1;
978 egressPort.$douerr <= pendingErrBlks[i];
979 pendingErrBlks[i] = 1'b0;
980 fillCplData( i*4 );
981 validDelay = urandom() % 5;
982 }
983
984 // Otherwise, there's nothing to do
985 // regarding the DOU.
986 else
987 {
988 egressPort.$douvalid <= 1'b0;
989 if ( validDelay > 0 ) validDelay = validDelay - 1;
990 }
991 }
992#endif
993 } /* end egressHdr */ /* Crude scheduling of DOU 'valid' */ /*???*/
994
995/*
996* egressData - Send data-out memory rows to the ILU
997*
998* Parameters: None
999*/
1000task DMUXtr::egressData()
1001 {
1002 bit [127:0] dataRow;
1003 bit [3:0] ptyErr;
1004 integer ptyErrOffs;
1005 bit [7:0] thisAddr;
1006 bit [7:0] priorAddr;
1007
1008#ifndef N2_FC
1009
1010
1011 priorAddr = 0;
1012 ptyErr = 0;
1013 while( 1 )
1014 {
1015 _WAIT_A_CYCLE;
1016 if ( egressPort.$addr >= 0 && egressPort.$addr <= 255 )
1017 {
1018 thisAddr = egressPort.$addr;
1019 dataRow = dataOutMemory[ egressPort.$addr ];
1020 if ( ptyErr == 0 || thisAddr != priorAddr )
1021 {
1022 ptyErrOffs = egressPort.$addr * 4;
1023 ptyErr = dataOutMemoryErr >> ptyErrOffs;
1024 dataOutMemoryErr = dataOutMemoryErr ^ (ptyErr << ptyErrOffs);
1025 }
1026 }
1027 else
1028 {
1029 dataRow = 128'b0;
1030 ptyErr = 4'b0;
1031 }
1032 if ( ptyErr != 0 && thisAddr != priorAddr )
1033 _INFO_MSG( "Injecting a DOU parity error! " );
1034// Shouldn't there be a cycle between the $addr and $data being valid?
1035 egressPort.$data = dataRow;
1036 egressPort.$par = ~{ ^dataRow[127:96], ^dataRow[95:64],
1037 ^dataRow[63:32], ^dataRow[31:0] }
1038 ^ { ptyErr[0], ptyErr[1], ptyErr[2], ptyErr[3] };
1039 priorAddr = thisAddr;
1040 }
1041#endif
1042 } /* end egressData */
1043
1044/*
1045* egressRel - Place release records from the ILU into the "egressRelQueue"
1046*
1047* Parameters: None
1048*
1049* NOTE: The entries in the "egressRelQueue" represent PIO read/write tags
1050* or DOU addresses. The high-order bit distinguishes the two (0=>tag).
1051*/
1052task DMUXtr::egressRel()
1053 {
1054 bit [8:0] relRecd;
1055
1056#ifndef N2_FC
1057 while( 1 )
1058 {
1059 _WAIT_A_CYCLE;
1060 if ( egressPort.$relrcdenq )
1061 {
1062 relRecd = egressPort.$relrcd;
1063
1064 if ( egressRelQueue == 0 )
1065 {
1066 _REPORT_ERROR( "ILU enqueues a release record before we're ready" );
1067 }
1068
1069 // If this release record releases
1070 // a DOU block, add it to the queue.
1071 else if ( relRecd[8] )
1072 {
1073 mailbox_put( egressRelQueue, {1'b1, 1'b0, relRecd[4:0], 2'b00} );
1074 }
1075
1076 // If this release record releases
1077 // a PIO write tag, then put
1078 // separate entries in the queue for
1079 // the tag and for the DOU block
1080 // associated with that tag.
1081 else
1082 {
1083 mailbox_put( egressRelQueue, {1'b1, 2'b10, relRecd[3:0], 2'b00} );
1084 mailbox_put( egressRelQueue, {1'b0, 4'b0001, relRecd[3:0]} );
1085 }
1086 }
1087 }
1088#endif
1089 } /* end egressRel */
1090
1091/*
1092* checkPecRecd - Compare a PEC record (from the ILU) against an expected
1093* TLP header (in PCI-Express format)
1094*
1095* Parameters:
1096* pecRecd - A PEC record taken from the ILU ingress pipeline
1097* tlpHdr - The expected TLP header
1098*
1099* Returned value: Non-zero if the record is unexpected (i.e. if the "pecRecd"
1100* and the "tlpHdr" disagree).
1101*
1102* NOTE: This procedure puts the offending header into the "cplQueue" if
1103* that mailbox exists (is non-zero) and if the "pecRecd" represents
1104* an unexpected unsuccessful completion.
1105*/
1106function bit DMUXtr::checkPecRecd( bit[PEC__RECD] pecRecd,
1107 bit[PEC_PCI__HDR] tlpHdr )
1108 {
1109 bit [6:0] expType; // Expected PEC format and type
1110 bit [6:0] lowaddrMask; // Significant bits in PEC recd
1111 bit [6:0] lowaddrZero; // Bits forced to zero by ILU
1112 bit [31:0] lowAddr; // Low-order 32-bits of addr
1113 string errMsg;
1114
1115 expType = {tlpHdr[PEC_PCI__FMT], tlpHdr[PEC_PCI__TYPE]};
1116 if ( tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_CFG0
1117 || tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_CFG1
1118 || tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_IO )
1119 {
1120 expType = PEC__TYPE_UR;
1121 }
1122 if ( { pecRecd[PEC__FMT], pecRecd[PEC__TYPE] } != expType
1123 || pecRecd[PEC__LEN] != tlpHdr[PEC_PCI__LEN]
1124 || pecRecd[PEC__TC] != tlpHdr[PEC_PCI__TC]
1125 || pecRecd[PEC__ATTR] != tlpHdr[PEC_PCI__ATTR] )
1126 {
1127 checkPecRecd = 1;
1128 }
1129 else if ( tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_CPL )
1130 {
1131 // Sorry, but there are different bits
1132 // of the "lowaddr" retained for CPL
1133 // records with and without data.
1134 if ( tlpHdr[PEC_PCI__FMT_DATA] )
1135 {
1136 lowaddrMask = PEC__LOWADDR_CPLD_MASK;
1137 lowaddrZero = PEC__LOWADDR_CPLD_ZERO;
1138 }
1139 else
1140 {
1141 lowaddrMask = PEC__LOWADDR_CPL_MASK;
1142 lowaddrZero = 0;
1143 }
1144
1145 if ( pecRecd[PEC__CPL_ID] != tlpHdr[PEC_PCI__CPL_ID]
1146 || pecRecd[PEC__CPL_STATUS] != tlpHdr[PEC_PCI__CPL_STATUS]
1147 || pecRecd[PEC__CPL_REQ_ID] != tlpHdr[PEC_PCI__CPL_REQ_ID]
1148 || pecRecd[PEC__CPL_TAG] != tlpHdr[PEC_PCI__CPL_TAG]
1149 || pecRecd[PEC__BCM] != tlpHdr[PEC_PCI__BCM]
1150 || pecRecd[PEC__BYTECOUNT] != tlpHdr[PEC_PCI__BYTECOUNT] )
1151 {
1152 checkPecRecd = 1;
1153 }
1154// else if ( ( pecRecd[PEC__LOWADDR] & lowaddrMask )
1155// != ( tlpHdr[PEC_PCI__LOWADDR] & lowaddrMask & ~lowaddrZero ) )
1156// {
1157// checkPecRecd = 1;
1158// }
1159 else
1160 {
1161 checkPecRecd = 0;
1162 }
1163 } /* end of CPL check */
1164 else if ( tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_MEM
1165 || tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_MEM_LK )
1166 {
1167 if ( pecRecd[PEC__REQ_ID] != tlpHdr[PEC_PCI__REQ_ID]
1168 || pecRecd[PEC__TLP_TAG] != tlpHdr[PEC_PCI__TLP_TAG]
1169 || pecRecd[PEC__FIRST_DWBE] != tlpHdr[PEC_PCI__FIRST_DWBE]
1170 || pecRecd[PEC__LAST_DWBE] != tlpHdr[PEC_PCI__LAST_DWBE]
1171 || ( pecRecd[PEC__FMT_4DW] &&
1172 pecRecd[PEC__ADDR] != tlpHdr[PEC_PCI__ADDR] )
1173 || ( !pecRecd[PEC__FMT_4DW] &&
1174 pecRecd[PEC__ADDR32] != tlpHdr[PEC_PCI__ADDR32] ) )
1175 {
1176 checkPecRecd = 1;
1177 }
1178 else
1179 {
1180 checkPecRecd = 0;
1181 }
1182 } /* end of MEM check */
1183 else if ( (tlpHdr[PEC_PCI__TYPE] & ~PEC_PCI__TYPE_MSG_RC_MASK)
1184 == PEC_PCI__TYPE_MSG )
1185 {
1186 if ( pecRecd[PEC__REQ_ID] != tlpHdr[PEC_PCI__REQ_ID]
1187 || pecRecd[PEC__TLP_TAG] != tlpHdr[PEC_PCI__TLP_TAG]
1188 || pecRecd[PEC__MSG_CODE] != tlpHdr[PEC_PCI__MSG_CODE] )
1189 {
1190 checkPecRecd = 1;
1191 }
1192 else
1193 {
1194 checkPecRecd = 0;
1195 }
1196 } /* end of MSG check */
1197 else if ( expType == PEC__TYPE_UR )
1198 {
1199 if ( tlpHdr[PEC_PCI__FMT_4DW] )
1200 lowAddr = tlpHdr[PEC_PCI__ADDR];
1201 else
1202 lowAddr = tlpHdr[PEC_PCI__ADDR32];
1203 if ( pecRecd[PEC__REQ_ID] != tlpHdr[PEC_PCI__REQ_ID]
1204 || pecRecd[PEC__TLP_TAG] != tlpHdr[PEC_PCI__TLP_TAG]
1205 || pecRecd[PEC__FIRST_DWBE] != tlpHdr[PEC_PCI__FIRST_DWBE]
1206 || pecRecd[PEC__LAST_DWBE] != tlpHdr[PEC_PCI__LAST_DWBE]
1207 || pecRecd[PEC__ADDR32] != lowAddr )
1208 {
1209 checkPecRecd = 1;
1210 }
1211 else
1212 {
1213 checkPecRecd = 0;
1214 }
1215 } /* end of unsupported request check */
1216 else
1217 {
1218 _REPORT_ERROR( "Internal error in 'chkPecRecd'... unexpected type" );
1219 checkPecRecd = 1;
1220 }
1221
1222 if( !checkPecRecd ){
1223 _DEBUG_MSG( psprintf("DMUXtr.checkPecRecd pecRecd Header matches expect tlpHdr=%h",tlpHdr) );
1224 }
1225 } /* end checkPecRecd */
1226
1227/*
1228* reportPecErr - Print an error describing a PEC record (from the ILU) and
1229* the expected TLP header (in PCI-Express format)
1230*
1231* Parameters:
1232* pecRecd - A PEC record taken from the ILU ingress pipeline
1233* tlpHdr - The expected TLP header
1234*/
1235task DMUXtr::reportPecErr( bit[PEC__RECD] pecRecd, bit[PEC_PCI__HDR] tlpHdr )
1236 {
1237 bit [6:0] expType; // Expected PEC format and type
1238 bit [6:0] lowaddrMask; // Significant bits in PEC recd
1239 bit [6:0] lowaddrZero; // Bits forced to zero by ILU
1240 string errMsg;
1241 bit [31:0] lowAddr;
1242
1243 expType = {tlpHdr[PEC_PCI__FMT], tlpHdr[PEC_PCI__TYPE]};
1244 if ( tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_CFG0
1245 || tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_CFG1
1246 || tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_IO )
1247 {
1248 expType = PEC__TYPE_UR;
1249 }
1250 if ( { pecRecd[PEC__FMT], pecRecd[PEC__TYPE] } != expType
1251 || pecRecd[PEC__LEN] != tlpHdr[PEC_PCI__LEN]
1252 || pecRecd[PEC__TC] != tlpHdr[PEC_PCI__TC]
1253 || pecRecd[PEC__ATTR] != tlpHdr[PEC_PCI__ATTR] )
1254 {
1255 _REPORT_ERROR( "Incorrect TLP hdr from ILU" );
1256 sprintf( errMsg, "Actual: FMT=%x TYPE=%x LEN=%x TC=%x ATTR=%x MSG_CODE=%x pecRecd=%h",
1257 pecRecd[PEC__FMT],
1258 pecRecd[PEC__TYPE],
1259 pecRecd[PEC__LEN],
1260 pecRecd[PEC__TC],
1261 pecRecd[PEC__ATTR],
1262 pecRecd[PEC__MSG_CODE],
1263 pecRecd
1264 );
1265 _ERROR_INFO( errMsg );
1266 sprintf( errMsg, "Expect: FMT=%x TYPE=%x LEN=%x TC=%x ATTR=%x MSG_CODE=%x tlpHdr=%h",
1267 expType[6:5],
1268 expType[4:0],
1269 tlpHdr[PEC_PCI__LEN],
1270 tlpHdr[PEC_PCI__TC],
1271 tlpHdr[PEC_PCI__ATTR],
1272 tlpHdr[PEC_PCI__MSG_CODE],
1273 tlpHdr
1274 );
1275
1276 _ERROR_INFO( errMsg );
1277 }
1278 else if ( tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_CPL )
1279 {
1280 // Sorry, but there are different bits
1281 // of the "lowaddr" retained for CPL
1282 // records with and without data.
1283 if ( tlpHdr[PEC_PCI__FMT_DATA] )
1284 {
1285 lowaddrMask = PEC__LOWADDR_CPLD_MASK;
1286 lowaddrZero = PEC__LOWADDR_CPLD_ZERO;
1287 }
1288 else
1289 {
1290 lowaddrMask = PEC__LOWADDR_CPL_MASK;
1291 lowaddrZero = 0;
1292 }
1293
1294 if ( pecRecd[PEC__CPL_ID] != tlpHdr[PEC_PCI__CPL_ID]
1295 || pecRecd[PEC__CPL_STATUS] != tlpHdr[PEC_PCI__CPL_STATUS]
1296 || pecRecd[PEC__CPL_REQ_ID] != tlpHdr[PEC_PCI__CPL_REQ_ID]
1297 || pecRecd[PEC__CPL_TAG] != tlpHdr[PEC_PCI__CPL_TAG]
1298 || pecRecd[PEC__BCM] != tlpHdr[PEC_PCI__BCM]
1299 || pecRecd[PEC__BYTECOUNT] != tlpHdr[PEC_PCI__BYTECOUNT]
1300 || ( pecRecd[PEC__LOWADDR] & lowaddrMask )
1301 != ( tlpHdr[PEC_PCI__LOWADDR] & lowaddrMask & ~lowaddrZero ) )
1302 {
1303 _REPORT_ERROR( "Incorrect completion from ILU" );
1304 sprintf( errMsg,
1305 "Actual: ID=%x STATUS=%x REQ=%x TAG=%x BCM=%x BCNT=%x LADDR=%x pecRecd=%h",
1306 pecRecd[PEC__CPL_ID],
1307 pecRecd[PEC__CPL_STATUS],
1308 pecRecd[PEC__CPL_REQ_ID],
1309 pecRecd[PEC__CPL_TAG],
1310 pecRecd[PEC__BCM],
1311 pecRecd[PEC__BYTECOUNT],
1312 pecRecd[PEC__LOWADDR] & lowaddrMask,
1313 pecRecd );
1314 _ERROR_INFO( errMsg );
1315 sprintf( errMsg,
1316 "Expect: ID=%x STATUS=%x REQ=%x TAG=%x BCM=%x BCNT=%x LADDR=%x tlpHdr=%h",
1317 tlpHdr[PEC_PCI__CPL_ID],
1318 tlpHdr[PEC_PCI__CPL_STATUS],
1319 tlpHdr[PEC_PCI__CPL_REQ_ID],
1320 tlpHdr[PEC_PCI__CPL_TAG],
1321 tlpHdr[PEC_PCI__BCM],
1322 tlpHdr[PEC_PCI__BYTECOUNT],
1323 tlpHdr[PEC_PCI__LOWADDR] & lowaddrMask & ~lowaddrZero,
1324 tlpHdr );
1325 _ERROR_INFO( errMsg );
1326 }
1327 } /* end of CPL check */
1328 else if ( tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_MEM
1329 || tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_MEM_LK )
1330 {
1331 if ( pecRecd[PEC__REQ_ID] != tlpHdr[PEC_PCI__REQ_ID]
1332 || pecRecd[PEC__TLP_TAG] != tlpHdr[PEC_PCI__TLP_TAG]
1333 || pecRecd[PEC__FIRST_DWBE] != tlpHdr[PEC_PCI__FIRST_DWBE]
1334 || pecRecd[PEC__LAST_DWBE] != tlpHdr[PEC_PCI__LAST_DWBE]
1335 || ( pecRecd[PEC__FMT_4DW] &&
1336 pecRecd[PEC__ADDR] != tlpHdr[PEC_PCI__ADDR] )
1337 || ( !pecRecd[PEC__FMT_4DW] &&
1338 pecRecd[PEC__ADDR32] != tlpHdr[PEC_PCI__ADDR32] ) )
1339 {
1340// Moved to end of if to allow error info to print
1341// _REPORT_ERROR( "Incorrect DMA memory request from ILU" );
1342 if ( pecRecd[PEC__FMT_4DW] )
1343 {
1344 sprintf( errMsg, "Actual: pecRecd=%x \n\t ID=%x TAG=%x DWBE=%x%x ADDR=%x",
1345 pecRecd,
1346 pecRecd[PEC__REQ_ID],
1347 pecRecd[PEC__TLP_TAG],
1348 pecRecd[PEC__LAST_DWBE],
1349 pecRecd[PEC__FIRST_DWBE],
1350 pecRecd[PEC__ADDR] );
1351 _ERROR_INFO( errMsg );
1352 sprintf( errMsg, "Expect: tlpHdr=%x \n\t ID=%x TAG=%x DWBE=%x%x ADDR=%x",
1353 tlpHdr,
1354 tlpHdr[PEC_PCI__REQ_ID],
1355 tlpHdr[PEC_PCI__TLP_TAG],
1356 tlpHdr[PEC_PCI__LAST_DWBE],
1357 tlpHdr[PEC_PCI__FIRST_DWBE],
1358 tlpHdr[PEC_PCI__ADDR] );
1359 _ERROR_INFO( errMsg );
1360 }
1361 else
1362 {
1363 sprintf( errMsg, "Actual: pecRecd=%x \n\t ID=%x TAG=%x DWBE=%x%x ADDR=%x",
1364 pecRecd,
1365 pecRecd[PEC__REQ_ID],
1366 pecRecd[PEC__TLP_TAG],
1367 pecRecd[PEC__LAST_DWBE],
1368 pecRecd[PEC__FIRST_DWBE],
1369 pecRecd[PEC__ADDR32] );
1370 _ERROR_INFO( errMsg );
1371 sprintf( errMsg, "Expect: tlpHdr=%x \n\t ID=%x TAG=%x DWBE=%x%x ADDR=%x",
1372 tlpHdr,
1373 tlpHdr[PEC_PCI__REQ_ID],
1374 tlpHdr[PEC_PCI__TLP_TAG],
1375 tlpHdr[PEC_PCI__LAST_DWBE],
1376 tlpHdr[PEC_PCI__FIRST_DWBE],
1377 tlpHdr[PEC_PCI__ADDR32] );
1378 _ERROR_INFO( errMsg );
1379 }
1380 _REPORT_ERROR( "Incorrect DMA memory request from ILU" );
1381 }
1382 } /* end of MEM check */
1383 else if ( (tlpHdr[PEC_PCI__TYPE] & ~PEC_PCI__TYPE_MSG_RC_MASK)
1384 == PEC_PCI__TYPE_MSG )
1385 {
1386 if ( pecRecd[PEC__REQ_ID] != tlpHdr[PEC_PCI__REQ_ID]
1387 || pecRecd[PEC__TLP_TAG] != tlpHdr[PEC_PCI__TLP_TAG]
1388 || pecRecd[PEC__MSG_CODE] != tlpHdr[PEC_PCI__MSG_CODE] )
1389 {
1390 sprintf( errMsg, "Actual: ID=%x TAG=%x CODE=%x pecRecd=%h",
1391 pecRecd[PEC__REQ_ID],
1392 pecRecd[PEC__TLP_TAG],
1393 pecRecd[PEC__MSG_CODE],
1394 pecRecd );
1395 _ERROR_INFO( errMsg );
1396 sprintf( errMsg, "Actual: PEC__FMT=%x PEC__TYPE=%x PEC__MSG_CODE=%x",
1397 pecRecd[PEC__FMT],
1398 pecRecd[PEC__TYPE],
1399 pecRecd[PEC__MSG_CODE]
1400 );
1401 _ERROR_INFO( errMsg );
1402 sprintf( errMsg, "Expect: ID=%x TAG=%x CODE=%x tlpHdr=%h",
1403 tlpHdr[PEC_PCI__REQ_ID],
1404 tlpHdr[PEC_PCI__TLP_TAG],
1405 tlpHdr[PEC_PCI__MSG_CODE],
1406 tlpHdr );
1407 _ERROR_INFO( errMsg );
1408 sprintf( errMsg, "Expect: PEC_PCI__FMT=%x PEC_PCI__TYPE=%x PEC_PCI__MSG_CODE=%x",
1409 tlpHdr[PEC_PCI__FMT],
1410 tlpHdr[PEC_PCI__TYPE],
1411 tlpHdr[PEC_PCI__MSG_CODE]
1412 );
1413 _ERROR_INFO( errMsg );
1414 _REPORT_ERROR( "Incorrect message from ILU" );
1415 }
1416 } /* end of MSG check */
1417 else if ( expType == PEC__TYPE_UR )
1418 {
1419 _REPORT_ERROR( "Incorrect 'unsupported request' from ILU" );
1420 if ( tlpHdr[PEC_PCI__FMT_4DW] )
1421 lowAddr = tlpHdr[PEC_PCI__ADDR];
1422 else
1423 lowAddr = tlpHdr[PEC_PCI__ADDR32];
1424 sprintf( errMsg, "Actual: ID=%x TAG=%x DWBE=%x%x ADDR=%x pecRecd=%h",
1425 pecRecd[PEC__REQ_ID],
1426 pecRecd[PEC__TLP_TAG],
1427 pecRecd[PEC__LAST_DWBE],
1428 pecRecd[PEC__FIRST_DWBE],
1429 lowAddr,
1430 pecRecd );
1431 _ERROR_INFO( errMsg );
1432 sprintf( errMsg, "Expect: ID=%x TAG=%x DWBE=%x%x ADDR=%x tlpHdr=%h",
1433 tlpHdr[PEC_PCI__REQ_ID],
1434 tlpHdr[PEC_PCI__TLP_TAG],
1435 tlpHdr[PEC_PCI__LAST_DWBE],
1436 tlpHdr[PEC_PCI__FIRST_DWBE],
1437 tlpHdr[PEC_PCI__ADDR32],
1438 tlpHdr );
1439 _ERROR_INFO( errMsg );
1440 } /* end of unsupported request check */
1441 else
1442 {
1443 _REPORT_ERROR( "Internal error in 'chkPecRecd'... unexpected type" );
1444 }
1445 } /* end reportPecErr */
1446
1447/*
1448* sendPecRecd - Present a PEC record to the ILU
1449*
1450* Parameters:
1451* tlpHdr - The TLP header (in PCI-Express format) to be represented
1452* douAddr - The starting DOU address for payload
1453*/
1454task DMUXtr::sendPecRecd( bit[PEC_PCI__HDR] tlpHdr, bit[7:0] douAddr )
1455 {
1456 bit[PEC__RECD] pecRecd;
1457#ifndef N2_FC
1458
1459 pecRecd = { urandom(), urandom(), urandom(), urandom() };
1460
1461 pecRecd[PEC__FMT] = tlpHdr[PEC_PCI__FMT];
1462 pecRecd[PEC__TYPE] = tlpHdr[PEC_PCI__TYPE];
1463 pecRecd[PEC__TC] = tlpHdr[PEC_PCI__TC];
1464 pecRecd[PEC__ATTR] = tlpHdr[PEC_PCI__ATTR];
1465 pecRecd[PEC__LEN] = tlpHdr[PEC_PCI__LEN];
1466
1467 if ( tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_CPL
1468 || tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_CPL_LK )
1469 {
1470 pecRecd[PEC__ADDR32] = 32'b0; // To clear bit above lowaddr
1471 pecRecd[PEC__CPL_ID] = tlpHdr[PEC_PCI__CPL_ID];
1472 pecRecd[PEC__CPL_STATUS] = tlpHdr[PEC_PCI__CPL_STATUS];
1473 pecRecd[PEC__CPL_REQ_ID] = tlpHdr[PEC_PCI__CPL_REQ_ID];
1474 pecRecd[PEC__CPL_TAG] = tlpHdr[PEC_PCI__CPL_TAG];
1475 pecRecd[PEC__BCM] = tlpHdr[PEC_PCI__BCM];
1476 pecRecd[PEC__BYTECOUNT] = tlpHdr[PEC_PCI__BYTECOUNT];
1477 pecRecd[PEC__LOWADDR] = tlpHdr[PEC_PCI__LOWADDR];
1478 pecRecd[PEC__D_PTR] = douAddr[7:2];
1479 }
1480
1481 else if ( tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_MEM ){
1482 pecRecd[PEC__REQ_ID] = tlpHdr[PEC_PCI__REQ_ID];
1483 pecRecd[PEC__TLP_TAG] = tlpHdr[PEC_PCI__TLP_TAG];
1484 pecRecd[PEC__FIRST_DWBE] = tlpHdr[PEC_PCI__FIRST_DWBE];
1485 pecRecd[PEC__LAST_DWBE] = tlpHdr[PEC_PCI__LAST_DWBE];
1486 if ( tlpHdr[PEC_PCI__FMT_4DW] ){
1487 pecRecd[PEC__ADDR] = tlpHdr[PEC_PCI__ADDR];
1488 }
1489 else{
1490 pecRecd[PEC__ADDR32] = tlpHdr[PEC_PCI__ADDR32];
1491 }
1492 if ( tlpHdr[PEC_PCI__FMT_DATA] ){
1493 //pecRecd[PEC__D_PTR] = douAddr[7:2];
1494 pecRecd[PEC__D_PTR] = {douAddr[7:6],douAddr[3:0]};
1495 }
1496 }
1497
1498 else /* if it's a config or I/O request... */
1499 {
1500 pecRecd[PEC__REQ_ID] = tlpHdr[PEC_PCI__REQ_ID];
1501 pecRecd[PEC__TLP_TAG] = tlpHdr[PEC_PCI__TLP_TAG];
1502 pecRecd[PEC__FIRST_DWBE] = tlpHdr[PEC_PCI__FIRST_DWBE];
1503 pecRecd[PEC__LAST_DWBE] = 4'b0000;
1504 pecRecd[PEC__ADDR32] = tlpHdr[PEC_PCI__ADDR32];
1505 if ( tlpHdr[PEC_PCI__FMT_DATA] )
1506 //pecRecd[PEC__D_PTR] = douAddr[7:2];
1507 pecRecd[PEC__D_PTR] = {douAddr[7:6],douAddr[3:0]};
1508 }
1509
1510 // - Shift data right by 2 bits since pecRecd is 126 bits and $recd is 124
1511 egressPort.$recd <= pecRecd >> 2;
1512
1513 _DEBUG_MSG( psprintf( "\nPEC RECORD (DMUXtr:sendpecrcd): \tFMT=%x TYPE=%x TC=%x ATTR=%x LEN=%x REQID=%x TAG=%x ADDR=%x LAST_DWBE=%x FIRST_DWBE=%x\n",
1514 pecRecd[PEC__FMT],
1515 pecRecd[PEC__TYPE],
1516 pecRecd[PEC__TC],
1517 pecRecd[PEC__ATTR],
1518 pecRecd[PEC__LEN],
1519 pecRecd[PEC__REQ_ID],
1520 pecRecd[PEC__TLP_TAG],
1521 pecRecd[PEC__ADDR],
1522 pecRecd[PEC__LAST_DWBE],
1523 pecRecd[PEC__FIRST_DWBE] )
1524 );
1525#endif
1526 } /* end sendPecRecd */
1527
1528/*
1529* fillDataOut - Put significant data into the DataOut memory
1530*
1531* Parameters:
1532* douAddr - The starting address of the DataOut memory
1533* dwCount - The number of DWs of data to initialize
1534* payload - The byte to fill the memory with
1535* gasDWs - The number of DWs of garbage before the first "payload" DW
1536* cplData - Is this data for a DMA-read completion?
1537*/
1538task DMUXtr::fillDataOut( bit[7:0] douAddr,
1539 integer dwCount,
1540 bit[7:0] payload,
1541 integer gasDWs,
1542 bit cplData )
1543 {
1544 bit [127:0] dataRow;
1545 bit [7:0] dataByte;
1546 bit [7:0] dataAddr;
1547 integer dwOffs;
1548 integer i;
1549 integer j;
1550
1551 dataRow = 128'b0;
1552 dataByte = payload;
1553 dataAddr = douAddr;
1554 dwOffs = 0;
1555
1556 _DEBUG_MSG( psprintf("DMUXtr::DMUXtr::fillDataOut douAddr=%h dwCount=%0d payload=%0h gasDWs=%0d \n",douAddr,dwCount,payload,gasDWs) );
1557 // Put as many DWs of "payload" into
1558 // the "dataOut" memory as required.
1559 for ( i=0; i<dwCount+gasDWs; i++ )
1560 {
1561 if ( i<gasDWs )
1562 dataRow = { dataRow[95:0], 32'hBabeF00D };
1563 else
1564 {
1565 // Add another DW of incrementing bytes.
1566 // OR a DW of stuff followed by zeros
1567 // if we're filling in the second and
1568 // subsequent blocks of a DMA completion
1569 for ( j=0; j<4; j++ )
1570 {
1571 if ( cplData && i >= 16 && j > 0 )
1572 dataRow = { dataRow[119:0], 8'b00 };
1573 else
1574 dataRow = { dataRow[119:0], dataByte };
1575 dataByte = dataByte + 1;
1576 }
1577 }
1578 dwOffs = dwOffs + 1;
1579
1580 // If this row is full, then add it to
1581 // the dataOut memory and increment
1582 // the address.
1583 if ( dwOffs == 4 )
1584 {
1585 dataOutMemory[dataAddr] = dataRow;
1586 if ( dataAddr == 8'h7f )
1587 dataAddr = 8'b0;
1588// else if ( dataAddr == 8'hbf )
1589 else if ( dataAddr == 8'h8f )
1590 dataAddr = 8'h80;
1591 else
1592 dataAddr = dataAddr + 1;
1593 dwOffs = 0;
1594 dataRow = 128'b0;
1595 }
1596 }
1597
1598 // If there is a partial row, then fill
1599 // it with junk DWs and add it to the
1600 // dataOut memory.
1601 if ( dwOffs != 0 )
1602 {
1603 while ( dwOffs < 4 )
1604 {
1605 dataRow = { dataRow[95:0], 32'hBabeF00D };
1606 dwOffs = dwOffs + 1;
1607 }
1608 dataOutMemory[dataAddr] = dataRow;
1609 }
1610
1611 } /* end fillDataOut */
1612
1613/*
1614* injectParityError - Inject a parity error into the "dataOutMemory"
1615*
1616* Parameters:
1617* douAddr - The starting address of the DataOut memory
1618* gasDWs - The number of DWs of garbage before the first "payload" DW
1619* errMask - Which bits should get clobbered?
1620*/
1621task DMUXtr::injectParityErr(bit[7:0] douAddr, integer gasDWs, bit[7:0] errMask)
1622 {
1623 integer i;
1624
1625 if ( errMask == 8'b0 )
1626 dataOutMemoryErr[ douAddr*4 + gasDWs ] = 1'b1;
1627 else
1628 {
1629 for ( i=0; i<8; i++ )
1630 if ( errMask[i] ) dataOutMemoryErr[ douAddr*4 + gasDWs + i ] = 1'b1;
1631 }
1632 } /* end injectParityErr */
1633
1634/*
1635* fillCplData - Put correct data into a now-valid dataOut memory block
1636*
1637* Parameters:
1638* douAddr - The starting address of the DataOut memory block (16 DWs)
1639*
1640* Each "incorrect" DW in the block has a correct high-order byte followed
1641* by either zeros (for "count") or ones (for "fill")
1642*/
1643task DMUXtr::fillCplData( bit[7:0] douAddr )
1644 {
1645 bit [127:0] dataRow;
1646 bit [7:0] dataAddr;
1647 integer i;
1648 integer j;
1649
1650 dataAddr = douAddr;
1651 for ( i=0; i<4; i++ )
1652 {
1653 dataRow = dataOutMemory[dataAddr];
1654 for ( j=0; j<4; j++ )
1655 {
1656 if ( dataRow[23:0] == 24'h000000 )
1657 {
1658 dataRow[23:16] = dataRow[31:24] + 1;
1659 dataRow[15:8] = dataRow[31:24] + 2;
1660 dataRow[7:0] = dataRow[31:24] + 3;
1661 }
1662 else if ( dataRow[23:0] == 24'hffffff )
1663 {
1664 dataRow[23:16] = dataRow[31:24];
1665 dataRow[15:8] = dataRow[31:24];
1666 dataRow[7:0] = dataRow[31:24];
1667 }
1668 dataRow = { dataRow[95:0], dataRow[127:96] };
1669 }
1670 dataOutMemory[dataAddr] = dataRow;
1671 dataAddr = dataAddr + 1;
1672 }
1673 } /* end fillCplData */
1674
1675/*
1676* enqueueIngressData - Add an entry to the "ingressDataQueue"
1677*
1678* Parameters:
1679* payload - The starting byte of the payload (with a high-order error bit)
1680* dwCount - The number of 4-byte DWs in the payload
1681* posted - Is the data associated with a posted DMA request?
1682*/
1683task DMUXtr::enqueueIngressData( bit[8:0] payload,
1684 integer dwCount,
1685 bit posted )
1686 {
1687 bit[15:0] count;
1688
1689 count = dwCount;
1690 mailbox_put( ingressDataQueue, {posted,count,payload} );
1691
1692 } /* end enqueueIngressData */
1693
1694/*
1695* dequeueIngressData - Get an entry from the "ingressDataQueue"
1696*
1697* Parameters:
1698* payload - The starting byte of the payload
1699* payloadErr - Is a parity error expected?
1700* dwCount - The number of 4-byte DWs in the payload
1701* posted - Is the data associated with a posted DMA request?
1702*/
1703task DMUXtr::dequeueIngressData( var bit[7:0] payload,
1704 var bit payloadErr,
1705 var integer dwCount,
1706 var bit posted )
1707 {
1708 bit [25:0] dataSpec;
1709
1710 void = mailbox_get( WAIT, ingressDataQueue, dataSpec );
1711 payload = dataSpec[7:0];
1712 payloadErr = dataSpec[8];
1713 dwCount = dataSpec[24:9];
1714 posted = dataSpec[25];
1715
1716 } /* end dequeueIngressData */
1717