// ========== Copyright Header Begin ==========================================
// OpenSPARC T2 Processor File: DMUXtr.vr
// Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved
// 4150 Network Circle, Santa Clara, California 95054, U.S.A.
// * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 2 of the License.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// For the avoidance of doubt, and except that if any non-GPL license
// choice is available it will apply instead, Sun elects to use only
// the General Public License version 2 (GPLv2) at this time for any
// software where a choice of GPL license versions is made
// available with the language indicating that GPLv2 or any later version
// may be used, or where a choice of which version of the GPL is applied is
// otherwise unspecified.
// Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
// CA 95054 USA or visit www.sun.com if you need additional information or
// ========== Copyright Header End ============================================
#include "report_info.vrh"
local po_DMUingress ingressPort;
local po_DMUegress egressPort;
local integer mutex; // A general-purpose mutex
local integer egressHdrQueue; // Mailbox: TLPs to send to the ILU
local integer egressQueue; // Mailbox: Parms for the hdr above
local integer egressEventQueue; // Mailbox: "send" completion events
local integer egressRelQueue; // External mailbox: release records
local integer ingressHdrQueue; // Mailbox: Expected TLPs from the ILU
local integer ingressQueue; // Mailbox: Parms for the hdr above
local integer ingressEventQueue; // Mailbox: "recv" completion events
local integer ingressDataQueue; // Mailbox: Data to be pulled from ILU
local integer ingressDataEventQueue; // Mailbox: Data to be pulled from ILU
local bit [7:0] ingressDataAddr; // Next IDB row to pull
local bit [127:0] dataOutMemory[256]; // Representing the DOU memory
local bit [1023:0] dataOutMemoryErr; // Should a parity error be injected?
local integer avgIngressCredits; // The target # of "ingressCredits"
local integer ingressCredits; // # of available ingress enq credits
local integer egressCredits; // # of available egress enq credits
local integer dequeuePending; // # of pending ingress credits to deq
local bit dequeueEnable; // Should we return ingress credits?
local integer dequeueMinDelay; // Min # of cycles between dequeues
local integer dequeueMaxDelay; // Max # of cycles between dequeues
local integer cplQueue; // A mailbox for unexpected bad cpl'ns
local bit ingressHdrLookAhead; // Has 'ingressHdr' pulled a header?
local bit disableUnusedParityCheck; // Should unused parity bits be ignored?
local bit debugOK; // Should debug messages be printed?
task new( po_DMUingress a_ingressPort, po_DMUegress a_egressPort, po_DMUmisc a_miscPort , ReportClass _Report );
task setRelMailbox( integer RelMailbox );
task setCplMailbox( integer CplMailbox );
task send( bit[PEC_PCI__HDR] tlpHdr,
task recv( bit[PEC_PCI__HDR] tlpHdr,
task setIngressDequeueDelay( integer MinDelay, integer MaxDelay );
task disableIngressDequeue();
task enableIngressDequeue();
task clear( bit TriggerExpectEvents );
task ignoreUnusedParity();
task setAvgIngressCreditsAvailable( integer Credits );
function integer ingressCreditsAvailable();
function integer egressCreditsAvailable();
// Threads manning the ILU interfaces...
local task ingressData(); // includes submitting release recds
// Some service routines...
bit checkPecRecd( bit[PEC__RECD] pecRecd, bit[PEC_PCI__HDR] tlpHdr );
local task reportPecErr( bit[PEC__RECD] pecRecd, bit[PEC_PCI__HDR] tlpHdr );
local task putCplQueue( bit[PEC__RECD] pecRecd );
local task sendPecRecd( bit[PEC_PCI__HDR] tlpHdr, bit[7:0] douAddr );
local task fillDataOut( bit[7:0] douAddr,
local task injectParityErr( bit[7:0] douAddr,
local task fillCplData( bit[7:0] douAddr );
local task enqueueIngressData( bit[8:0] payload,
local task dequeueIngressData( var bit[7:0] payload,
#define _WAIT_A_CYCLE @1 egressPort.$enq = void
#define _REPORT_ERROR(msg) Report.report(RTYP_TEST_ERROR,"DMUXtr (cycle %d) %s\n", get_cycle(), msg)
//#define _REPORT_ERROR(msg) error("DMUXtr (cycle %d) %s\n", get_cycle(), msg)
#define _ERROR_INFO(msg) printf("DMUXtr (cycle %d) %s\n", get_cycle(), msg)
#define _INFO_MSG(msg) printf("DMUXtr (cycle %d) %s\n", get_cycle(), msg)
#define _DEBUG_MSG(msg) if ( debugOK ) _INFO_MSG(msg)
#define _ACQUIRE_MUTEX void = semaphore_get(WAIT,mutex,1)
#define _RELEASE_MUTEX semaphore_put(mutex,1)
* new - Allocate a DMU transactor
task DMUXtr::new( po_DMUingress a_ingressPort, po_DMUegress a_egressPort, po_DMUmisc a_miscPort, ReportClass _Report )
ingressPort = a_ingressPort;
egressPort = a_egressPort;
miscPort.$pwrOnRstN <= 1'b0;
miscPort.$resetN <= 1'b0;
egressPort.$douvalid <= 1'b0;
egressPort.$douerr <= 1'b0;
// Everything is allocated by "enableXtr"
// "setCplQueue" tells us about a mailbox to put unexpected unsuccessful cplns
dataOutMemoryErr = 1024'b0;
disableUnusedParityCheck = 0;
// for( i=0; i<256; i++ ){
// dataOutMemory[i] = {96'hdeadbeefdeadbeefdeadbeefdead00,i};
// debugOK = get_plus_arg(CHECK,"DMUDUMP");
if (Report.get_global_print_threshold() < RPRT_DEBUG_1) {
* setRelMailbox - Establish a mailbox for sending ILU release records
* RelMailbox - The mailbox to receive ILU release records (egress)
* This task is called by the test environment to allow it to receive
* information on PIO tags and DOU blocks released by the ILU. Each mailbox
* entry is nine-bits, with the high-order bit indicating a released DOU block
* (followed by the starting DOU address of the released block).
task DMUXtr::setRelMailbox( integer RelMailbox )
egressRelQueue = RelMailbox;
} /* end setRelMailbox */
* setCplMailbox - Establish a mailbox for sending unexpected unsuccessful cplns
* CplMailbox - The mailbox to receive those bad-boy headers
* This task is called by the test environment to allow it to receive
* the headers for completion-TLPs which are unexpected (i.e. not specified
* by a "recv" call) and unsuccessful (i.e. PEC_PCI__CPL_STATUS is non-zero).
* If this mailbox is not set, then these unexpected headers (like any other
* unexpected TLP) will be recorded as an error.
task DMUXtr::setCplMailbox( integer CplMailbox )
} /* end setCplMailbox */
* enableXtr - Initialize all local variables and start manning the ports!
// The ingress and egress pipelines
// both start with credits.
ingressCredits = PEC_ILU_INGRESS_CREDITS; //6 credits
egressCredits = PEC_ILU_EGRESS_CREDITS; //4 credits
// A mutex for local critical sections
mutex = alloc(SEMAPHORE,0,1,1);
// The ingress and egress pipelines
// each have three queues, one holding
// the TLP header which is expected or
// is to be sent, and another holding
// "other" data given to send/recv, and
// a final queue holding events which
ingressQueue = alloc(MAILBOX,0,1);
ingressHdrQueue = alloc(MAILBOX,0,1);
ingressEventQueue = alloc(MAILBOX,0,1);
egressQueue = alloc(MAILBOX,0,1);
egressHdrQueue = alloc(MAILBOX,0,1);
egressEventQueue = alloc(MAILBOX,0,1);
ingressHdrLookAhead = 1'b0;
// A separate queue holds expected
// data to be pulled by an "ingressData"
// thread, and events to trigger.
ingressDataQueue = alloc(MAILBOX,0,1);
ingressDataEventQueue = alloc(MAILBOX,0,1);
// Start threads for ingress/egress
// TLP headers and payload.
// The "egressHdr" thread takes care of
// monitoring the egress "deq" signal,
// while a separate thread has the job
// of asserting it on the ingress side.
* send - Add a TLP to the egress pipeline
* tlpHdr - The TLP header (PCI-Express format) to be sent
* payload - The payload specification
* douAddr - The starting data-out address for payload
task DMUXtr::send( bit[PEC_PCI__HDR] tlpHdr,
bit[7:0] poisonedPayload;
payloadByte = payload[7:0];
poisonedPayload = payload[15:8];
fillPayload = payload[16];
errPayload = payload[17];
errMask = payload[25:18];
// Add a cleared event to the egress
mailbox_put( egressEventQueue, allDone );
// Add the header to the ingress
// header queue, and put the data
// specification in the control queue.
// The data-out memory is initialized
// just before the header is sent.
_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",
tlpHdr[PEC__FIRST_DWBE] )
mailbox_put( egressHdrQueue, tlpHdr );
mailbox_put( egressQueue, {errMask,errPayload,poisonedPayload,payloadByte,douAddr} );
// Wait for the TLP to be sent.
* recv - Add a TLP to the ingress pipeline expect-queue
* tlpHdr - The expected TLP header
* payload - The payload specification
task DMUXtr::recv( bit[PEC_PCI__HDR] tlpHdr,
_DEBUG_MSG( psprintf("DMUXtr::recv time = %d, DMUXtr.recv(tlpHdr=128'h%0h, payload=32'h%0h\n",get_time(LO), tlpHdr,payload));
payloadByte = payload[7:0];
payloadErr = payload[14]; // The "erroneous" bit from the env't
// Add a cleared event to the ingress
mailbox_put( ingressEventQueue, allDone );
// Add the header and payload-spec
// to the appropriate ingress queues.
mailbox_put( ingressHdrQueue, tlpHdr );
mailbox_put( ingressQueue, {optional,payloadErr,payloadByte} );
// Wait for the TLP to arrive.
* setAvgIngressCreditsAvailable - Set the number of "enqueue" credits that
* the ILU has available (on average)
* Credits - The target average value of "ingressCreditsAvailable" (below)
* NOTE: If "Credits" is out of range (i.e. negative), then the transactor
* picks an average (target) value, and changes it periodically.
task DMUXtr::setAvgIngressCreditsAvailable( integer Credits )
if ( Credits < 0 || Credits > PEC_ILU_INGRESS_CREDITS )
avgIngressCredits = Credits;
} /* end setAvgIngressCreditsAvailable */
* ingressCreditsAvailable - How many enqueue credits does the ILU have?
function integer DMUXtr::ingressCreditsAvailable()
ingressCreditsAvailable = ingressCredits;
* egressCreditsAvailable - How many enqueue credits does the DMU have?
function integer DMUXtr::egressCreditsAvailable()
egressCreditsAvailable = egressCredits;
* setIngressDequeueDelay - Set the minimum and maximum number of cycles before
* returning an ingress header credit to the ILU.
* MinDelay - The minimum delay from one "dequeue" to the next
* MaxDelay - The maximum such delay
task DMUXtr::setIngressDequeueDelay( integer MinDelay, integer MaxDelay )
if ( MinDelay >= 0 && MaxDelay >= MinDelay )
dequeueMinDelay = MinDelay;
dequeueMaxDelay = MaxDelay;
* disableIngressDequeue - Stop returning ingress header credits to the ILU.
task DMUXtr::disableIngressDequeue()
} /* end disableIngressDequeue */
* enableIngressDequeue - Resume returning ingress header credits to the ILU
task DMUXtr::enableIngressDequeue()
} /* end enableIngressDequeue */
* clear - Clear ingress expected TLPs
task DMUXtr::clear( bit TriggerExpectEvents )
bit [PEC_PCI__HDR] tlpHdr;
while( mailbox_get(NO_WAIT,ingressHdrQueue) > 0 )
void = mailbox_get( NO_WAIT, ingressHdrQueue, tlpHdr );
void = mailbox_get( NO_WAIT, ingressQueue, payload );
void = mailbox_get( NO_WAIT, ingressEventQueue, allDone );
if ( allDone != null && TriggerExpectEvents ) trigger( ONE_SHOT, allDone );
while( mailbox_get(NO_WAIT, ingressDataQueue) > 0 )
void = mailbox_get( NO_WAIT, ingressDataQueue, tlpHdr );
* reset - Put everything(?) back to where it was when we started
bit [PEC_PCI__HDR] tlpHdr;
ingressPort.$addr <= 8'b0;
dataOutMemoryErr = 1024'b0;
ingressCredits = PEC_ILU_INGRESS_CREDITS;
egressCredits = PEC_ILU_EGRESS_CREDITS;
while( mailbox_get(NO_WAIT,ingressHdrQueue) > 0 )
void = mailbox_get( NO_WAIT, ingressHdrQueue, tlpHdr );
void = mailbox_get( NO_WAIT, ingressQueue, payload );
void = mailbox_get( NO_WAIT, ingressEventQueue, allDone );
while( mailbox_get(NO_WAIT, ingressDataQueue) > 0 )
void = mailbox_get( NO_WAIT, ingressDataQueue, tlpHdr );
while( mailbox_get( NO_WAIT, egressHdrQueue ) > 0 )
void = mailbox_get( NO_WAIT, egressHdrQueue, tlpHdr );
void = mailbox_get( NO_WAIT, egressQueue, tlpSpec );
void = mailbox_get( NO_WAIT, egressEventQueue, allDone );
* ignoreUnusedParity - Don't report an error if parity from the IDB is not
* correct for DWs which are not part of the original TLP.
task DMUXtr::ignoreUnusedParity()
disableUnusedParityCheck = 1;
} /* end ignoreUnusedParity */
* ingressHdr - Monitor the ILU's ingress PEC port and make sure that
* everything that comes out is expected
task DMUXtr::ingressHdr()
bit [PEC_PCI__HDR] tlpHdr;
while( reset_pending ) _WAIT_A_CYCLE;
// If the ILU is presenting a PEC recd,
// ...make sure that it has a credit
if ( ingressCredits == 0 )
_REPORT_ERROR( "Ingress PEC record enqueued with no credits available");
// ...and that a record is expected...
else if ( !ingressHdrLookAhead && mailbox_get(NO_WAIT,ingressQueue) == 0 )
if ( ingressPort.$recd[PEC__TYPE] == PEC_PCI__TYPE_CPL
&& ingressPort.$recd[PEC__CPL_STATUS] != 0
putCplQueue( ingressPort.$recd );
tmp = { "Ingress PEC record enqueued when none expected: ",
psprintf("PEC__TYPE='d%0d, CPL_STATUS='d%0d, cplQueue=%0d",
ingressPort.$recd[PEC__TYPE],
ingressPort.$recd[PEC__CPL_STATUS],
// ...and then check the presented PEC
// record against the expected TLP
// header. Any payload is checked by
// the "ingressData" thread.
if ( !ingressHdrLookAhead )
void = mailbox_get( NO_WAIT, ingressHdrQueue, tlpHdr );
void = mailbox_get( NO_WAIT, ingressQueue, stuff );
void = mailbox_get( NO_WAIT, ingressEventQueue, allDone );
// Skip past optional TLPs which
// don't match what we've got.
&& mailbox_get(NO_WAIT,ingressQueue) > 0
&& checkPecRecd( ingressPort.$recd, tlpHdr ) )
void = mailbox_get( NO_WAIT, ingressHdrQueue, tlpHdr );
void = mailbox_get( NO_WAIT, ingressQueue, stuff );
void = mailbox_get( NO_WAIT, ingressEventQueue, allDone );
// If the PEC record doesn't match...
if ( checkPecRecd( ingressPort.$recd, tlpHdr ) )
// ...then either put an unsuccessful
// completion into the "cplQueue"...
if ( ingressPort.$recd[PEC__TYPE] == PEC_PCI__TYPE_CPL
&& ingressPort.$recd[PEC__CPL_STATUS] != 0
putCplQueue( ingressPort.$recd );
// ...or complain mightily.
reportPecErr( ingressPort.$recd, tlpHdr );
// And if the (matching) TLP has data
// then tell the "ingressData" thread
// to check the payload's validity.
else if ( ingressPort.$recd[PEC__FMT_DATA] )
mailbox_put( ingressDataEventQueue, allDone );
enqueueIngressData( payload,
ingressPort.$recd[PEC__LEN],
ingressPort.$recd[PEC__TYPE]!=PEC_PCI__TYPE_CPL );
// Otherwise, just signal whoever
// expected the TLP that we got it!
// The ILU has consumed a credit.
// The "ingressDeq" thread will take
// care of returning the credit.
ingressCredits = ingressCredits - 1;
dequeuePending = dequeuePending + 1;
if ( ingressCredits == 0 ) _DEBUG_MSG( "Ingress credits exhausted" );
} /* end "if ingressPort.$enq is asserted..." */
* putCplQueue - Add a TLP (a CPL header) to the "cplQueue"
* pecRecd - The PEC record denoting the TLP to be added to the "cplQueue"
task DMUXtr::putCplQueue( bit[PEC__RECD] pecRecd )
pciHdr[PEC_PCI__FMT] = pecRecd[PEC__FMT];
pciHdr[PEC_PCI__TYPE] = pecRecd[PEC__TYPE];
pciHdr[PEC_PCI__LEN] = pecRecd[PEC__LEN];
pciHdr[PEC_PCI__TC] = pecRecd[PEC__TC];
pciHdr[PEC_PCI__ATTR] = pecRecd[PEC__ATTR];
pciHdr[PEC_PCI__CPL_ID] = pecRecd[PEC__CPL_ID];
pciHdr[PEC_PCI__CPL_STATUS] = pecRecd[PEC__CPL_STATUS];
pciHdr[PEC_PCI__CPL_REQ_ID] = pecRecd[PEC__CPL_REQ_ID];
pciHdr[PEC_PCI__CPL_TAG] = pecRecd[PEC__CPL_TAG];
pciHdr[PEC_PCI__BCM] = pecRecd[PEC__BCM];
pciHdr[PEC_PCI__LOWADDR] = pecRecd[PEC__LOWADDR];
mailbox_put( cplQueue, pciHdr );
* ingressData - Pull data from the IDB and make sure that it matches the
* NOTE: The current implementation assumes a one-cycle IDB delay
task DMUXtr::ingressData()
ingressPort.$addr = 8'b0;
ingressPort.$relrcdenq = 1'b0;
while( reset_pending ) { printf( "Waiting for reset...\n" ); _WAIT_A_CYCLE;}
// Wait for some data to pull...
dequeueIngressData( payload, payloadErr, dwCount, posted );
// Make sure that the payload is
rowCount = (dwCount+3) / 4;
// - put a randomized delay here since data doesn't have to come back right away
// We've got the IDB row of interest
// (or more correctly its address)
// already in the pipeline. Go ahead
nextAddr = ingressDataAddr + 1;
ingressPort.$addr = nextAddr;
while( byteCount > 0 && !reset_pending)
dataRow = ingressPort.$data;
goodParity = ~{ ^dataRow[127:96], ^dataRow[95:64],
^dataRow[63:32], ^dataRow[31:0] };
if ( ingressPort.$par != goodParity && disableUnusedParityCheck )
if ( byteCount <= 12 ) goodParity[3] = ingressPort.$par[3];
if ( byteCount <= 8 ) goodParity[2] = ingressPort.$par[2];
if ( byteCount <= 4 ) goodParity[1] = ingressPort.$par[1];
if ( ingressPort.$par != goodParity )
_REPORT_ERROR( "Incorrect data parity from IDB" );
for ( i=0; i<16 && byteCount>0; i++ )
if ( dataRow[127:120] != payload )
_REPORT_ERROR( "Incorrect payload from IDB" );
sprintf( errMsg, "Expect: %x Actual: %x", payload, dataRow[127:120]);
dataRow = {dataRow[119:0],8'b0};
byteCount = byteCount - 1;
// Tell the ILU that we're all done
ingressPort.$relrcdenq = 1'b1;
ingressPort.$relrcd = {posted,ingressDataAddr};
ingressDataAddr = ingressDataAddr + 1;
// We're done with this row... get the
ingressPort.$addr = nextAddr;
} /* end "while there's payload to check..." */
if ( payloadErr && !payloadErrFound )
_REPORT_ERROR( "No data parity error detected when one is expected" );
// Tell whoever that we've finished
// looking at the payload.
void = mailbox_get( NO_WAIT, ingressDataEventQueue, allDone );
if ( !reset_pending ) trigger( ON, allDone );
// Stop sending release records.
ingressPort.$relrcdenq = 1'b0;
* ingressDeq - Return PEC record credits to the ILU
task DMUXtr::ingressDeq()
//Initialize rcd_deq signal
// If there's a dequeue to process and
// if we don't have a "delay" value,
// then now's a good time to get one.
// Use the max delay if the ILU has
// far too many credits, and the min
if ( dequeuePending > 0 && deqDelay < 0 )
if ( ingressCredits > avgIngressCredits + 2 )
else if ( ingressCredits > avgIngressCredits )
deqDelay = dequeueMaxDelay;
else if ( ingressCredits < avgIngressCredits - 1 )
deqDelay = dequeueMinDelay;
else if ( dequeueMinDelay < dequeueMaxDelay )
deqDelay = dequeueMinDelay
+ (urandom() % (dequeueMaxDelay-dequeueMinDelay+1) );// set to range min,max
deqDelay = dequeueMinDelay;
// If there are credits to be returned
// and if we've waited long enough...
if ( dequeuePending > 0 && deqDelay == 0 && dequeueEnable )
// ...assert the "dequeue" signal.
dequeuePending = dequeuePending - 1;
if ( dequeuePending == 0 ) deqDelay = -1;
ingressCredits = ingressCredits + 1;
if ( deqDelay > 0 ) deqDelay = deqDelay - 1;
* egressHdr - Supply PEC records from the "egressQueue" to the ILU
bit [PEC_PCI__HDR] tlpHdr;
bit [31:0] pendingDouBlks;
bit [31:0] pendingErrBlks;
bit ptyErr; // Inject a parity error in the firstDW?
while( reset_pending ) _WAIT_A_CYCLE;
// If the ILU has raised the "deq"
// signal, then we have a credit!
if ( egressCredits == PEC_ILU_EGRESS_CREDITS )
_REPORT_ERROR( "ILU raises 'deq' when no credit is expected" );
egressCredits = egressCredits + 1;
// If we've got a TLP to send and if
// we've got a credit and if we've
// waited long enough, then just do it!
if ( mailbox_get( NO_WAIT, egressQueue ) > 0
egressCredits = egressCredits - 1;
void = mailbox_get( NO_WAIT, egressHdrQueue, tlpHdr );
void = mailbox_get( NO_WAIT, egressQueue, tlpSpec );
void = mailbox_get( NO_WAIT, egressEventQueue, allDone );
ptyErrMask = tlpSpec[32:25];
poison = { 1'b0, tlpSpec[23:16] };
if ( tlpHdr[PEC_PCI__FMT_DATA] )
if ( tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_CPL )
tlpAddr = tlpHdr[PEC_PCI__LOWADDR];
egressPort.$douaddr <= douAddr[6:2];
tlpAddr = tlpHdr[PEC_PCI__FMT_4DW] ? tlpHdr[PEC_PCI__ADDR]
: tlpHdr[PEC_PCI__ADDR32];
fillDataOut( douAddr, tlpHdr[PEC_PCI__LEN], payload, gasDWs, sendCplD );
_DEBUG_MSG( psprintf("DMUXtr.egressHdr ptyErr is set calling injectParityErr tag=%0h douAddr=%0h payload=%0h gasDWs=%0h ",
tlpHdr[PEC__TLP_TAG],douAddr,payload,gasDWs) );
injectParityErr( douAddr, gasDWs, ptyErrMask );
sendPecRecd( tlpHdr, douAddr );
if ( enqDelay > 0 ) enqDelay = enqDelay - 1;
// If we sent a DMA completion with data
// then tell the ILU that the block is
// valid and record the other blocks
// which must be made valid before the
// ILU can present the TLP to the TLU.
egressPort.$douvalid <= 1'b1;
egressPort.$douerr <= poison[0];
douBlkCount = (gasDWs + tlpHdr[PEC_PCI__LEN] + 15) / 16;
for ( i=1; i<douBlkCount; i++ )
pendingDouBlks[ (douAddr[6:2]+i) % 32 ] = 1'b1;
pendingErrBlks[ (douAddr[6:2]+i) % 32 ] = poison[i];
// Otherwise, if there are DOU blocks
// to be made valid, then pick one.
else if ( validDelay==0 && pendingDouBlks != 32'b0 && (urandom() % 4)==0 )
while( pendingDouBlks[i] == 1'b0 ) i = (i+11)%32;
pendingDouBlks[i] = 1'b0;
egressPort.$douaddr <= i;
egressPort.$douvalid <= 1'b1;
egressPort.$douerr <= pendingErrBlks[i];
pendingErrBlks[i] = 1'b0;
validDelay = urandom() % 5;
// Otherwise, there's nothing to do
egressPort.$douvalid <= 1'b0;
if ( validDelay > 0 ) validDelay = validDelay - 1;
} /* end egressHdr */ /* Crude scheduling of DOU 'valid' */ /*???*/
* egressData - Send data-out memory rows to the ILU
task DMUXtr::egressData()
if ( egressPort.$addr >= 0 && egressPort.$addr <= 255 )
thisAddr = egressPort.$addr;
dataRow = dataOutMemory[ egressPort.$addr ];
if ( ptyErr == 0 || thisAddr != priorAddr )
ptyErrOffs = egressPort.$addr * 4;
ptyErr = dataOutMemoryErr >> ptyErrOffs;
dataOutMemoryErr = dataOutMemoryErr ^ (ptyErr << ptyErrOffs);
if ( ptyErr != 0 && thisAddr != priorAddr )
_INFO_MSG( "Injecting a DOU parity error! " );
// Shouldn't there be a cycle between the $addr and $data being valid?
egressPort.$data = dataRow;
egressPort.$par = ~{ ^dataRow[127:96], ^dataRow[95:64],
^dataRow[63:32], ^dataRow[31:0] }
^ { ptyErr[0], ptyErr[1], ptyErr[2], ptyErr[3] };
* egressRel - Place release records from the ILU into the "egressRelQueue"
* NOTE: The entries in the "egressRelQueue" represent PIO read/write tags
* or DOU addresses. The high-order bit distinguishes the two (0=>tag).
if ( egressPort.$relrcdenq )
relRecd = egressPort.$relrcd;
if ( egressRelQueue == 0 )
_REPORT_ERROR( "ILU enqueues a release record before we're ready" );
// If this release record releases
// a DOU block, add it to the queue.
mailbox_put( egressRelQueue, {1'b1, 1'b0, relRecd[4:0], 2'b00} );
// If this release record releases
// a PIO write tag, then put
// separate entries in the queue for
// the tag and for the DOU block
// associated with that tag.
mailbox_put( egressRelQueue, {1'b1, 2'b10, relRecd[3:0], 2'b00} );
mailbox_put( egressRelQueue, {1'b0, 4'b0001, relRecd[3:0]} );
* checkPecRecd - Compare a PEC record (from the ILU) against an expected
* TLP header (in PCI-Express format)
* pecRecd - A PEC record taken from the ILU ingress pipeline
* tlpHdr - The expected TLP header
* Returned value: Non-zero if the record is unexpected (i.e. if the "pecRecd"
* and the "tlpHdr" disagree).
* NOTE: This procedure puts the offending header into the "cplQueue" if
* that mailbox exists (is non-zero) and if the "pecRecd" represents
* an unexpected unsuccessful completion.
function bit DMUXtr::checkPecRecd( bit[PEC__RECD] pecRecd,
bit[PEC_PCI__HDR] tlpHdr )
bit [6:0] expType; // Expected PEC format and type
bit [6:0] lowaddrMask; // Significant bits in PEC recd
bit [6:0] lowaddrZero; // Bits forced to zero by ILU
bit [31:0] lowAddr; // Low-order 32-bits of addr
expType = {tlpHdr[PEC_PCI__FMT], tlpHdr[PEC_PCI__TYPE]};
if ( tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_CFG0
|| tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_CFG1
|| tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_IO )
if ( { pecRecd[PEC__FMT], pecRecd[PEC__TYPE] } != expType
|| pecRecd[PEC__LEN] != tlpHdr[PEC_PCI__LEN]
|| pecRecd[PEC__TC] != tlpHdr[PEC_PCI__TC]
|| pecRecd[PEC__ATTR] != tlpHdr[PEC_PCI__ATTR] )
else if ( tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_CPL )
// Sorry, but there are different bits
// of the "lowaddr" retained for CPL
// records with and without data.
if ( tlpHdr[PEC_PCI__FMT_DATA] )
lowaddrMask = PEC__LOWADDR_CPLD_MASK;
lowaddrZero = PEC__LOWADDR_CPLD_ZERO;
lowaddrMask = PEC__LOWADDR_CPL_MASK;
if ( pecRecd[PEC__CPL_ID] != tlpHdr[PEC_PCI__CPL_ID]
|| pecRecd[PEC__CPL_STATUS] != tlpHdr[PEC_PCI__CPL_STATUS]
|| pecRecd[PEC__CPL_REQ_ID] != tlpHdr[PEC_PCI__CPL_REQ_ID]
|| pecRecd[PEC__CPL_TAG] != tlpHdr[PEC_PCI__CPL_TAG]
|| pecRecd[PEC__BCM] != tlpHdr[PEC_PCI__BCM]
|| pecRecd[PEC__BYTECOUNT] != tlpHdr[PEC_PCI__BYTECOUNT] )
// else if ( ( pecRecd[PEC__LOWADDR] & lowaddrMask )
// != ( tlpHdr[PEC_PCI__LOWADDR] & lowaddrMask & ~lowaddrZero ) )
else if ( tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_MEM
|| tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_MEM_LK )
if ( pecRecd[PEC__REQ_ID] != tlpHdr[PEC_PCI__REQ_ID]
|| pecRecd[PEC__TLP_TAG] != tlpHdr[PEC_PCI__TLP_TAG]
|| pecRecd[PEC__FIRST_DWBE] != tlpHdr[PEC_PCI__FIRST_DWBE]
|| pecRecd[PEC__LAST_DWBE] != tlpHdr[PEC_PCI__LAST_DWBE]
|| ( pecRecd[PEC__FMT_4DW] &&
pecRecd[PEC__ADDR] != tlpHdr[PEC_PCI__ADDR] )
|| ( !pecRecd[PEC__FMT_4DW] &&
pecRecd[PEC__ADDR32] != tlpHdr[PEC_PCI__ADDR32] ) )
else if ( (tlpHdr[PEC_PCI__TYPE] & ~PEC_PCI__TYPE_MSG_RC_MASK)
if ( pecRecd[PEC__REQ_ID] != tlpHdr[PEC_PCI__REQ_ID]
|| pecRecd[PEC__TLP_TAG] != tlpHdr[PEC_PCI__TLP_TAG]
|| pecRecd[PEC__MSG_CODE] != tlpHdr[PEC_PCI__MSG_CODE] )
else if ( expType == PEC__TYPE_UR )
if ( tlpHdr[PEC_PCI__FMT_4DW] )
lowAddr = tlpHdr[PEC_PCI__ADDR];
lowAddr = tlpHdr[PEC_PCI__ADDR32];
if ( pecRecd[PEC__REQ_ID] != tlpHdr[PEC_PCI__REQ_ID]
|| pecRecd[PEC__TLP_TAG] != tlpHdr[PEC_PCI__TLP_TAG]
|| pecRecd[PEC__FIRST_DWBE] != tlpHdr[PEC_PCI__FIRST_DWBE]
|| pecRecd[PEC__LAST_DWBE] != tlpHdr[PEC_PCI__LAST_DWBE]
|| pecRecd[PEC__ADDR32] != lowAddr )
} /* end of unsupported request check */
_REPORT_ERROR( "Internal error in 'chkPecRecd'... unexpected type" );
_DEBUG_MSG( psprintf("DMUXtr.checkPecRecd pecRecd Header matches expect tlpHdr=%h",tlpHdr) );
* reportPecErr - Print an error describing a PEC record (from the ILU) and
* the expected TLP header (in PCI-Express format)
* pecRecd - A PEC record taken from the ILU ingress pipeline
* tlpHdr - The expected TLP header
task DMUXtr::reportPecErr( bit[PEC__RECD] pecRecd, bit[PEC_PCI__HDR] tlpHdr )
bit [6:0] expType; // Expected PEC format and type
bit [6:0] lowaddrMask; // Significant bits in PEC recd
bit [6:0] lowaddrZero; // Bits forced to zero by ILU
expType = {tlpHdr[PEC_PCI__FMT], tlpHdr[PEC_PCI__TYPE]};
if ( tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_CFG0
|| tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_CFG1
|| tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_IO )
if ( { pecRecd[PEC__FMT], pecRecd[PEC__TYPE] } != expType
|| pecRecd[PEC__LEN] != tlpHdr[PEC_PCI__LEN]
|| pecRecd[PEC__TC] != tlpHdr[PEC_PCI__TC]
|| pecRecd[PEC__ATTR] != tlpHdr[PEC_PCI__ATTR] )
_REPORT_ERROR( "Incorrect TLP hdr from ILU" );
sprintf( errMsg, "Actual: FMT=%x TYPE=%x LEN=%x TC=%x ATTR=%x MSG_CODE=%x pecRecd=%h",
sprintf( errMsg, "Expect: FMT=%x TYPE=%x LEN=%x TC=%x ATTR=%x MSG_CODE=%x tlpHdr=%h",
tlpHdr[PEC_PCI__MSG_CODE],
else if ( tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_CPL )
// Sorry, but there are different bits
// of the "lowaddr" retained for CPL
// records with and without data.
if ( tlpHdr[PEC_PCI__FMT_DATA] )
lowaddrMask = PEC__LOWADDR_CPLD_MASK;
lowaddrZero = PEC__LOWADDR_CPLD_ZERO;
lowaddrMask = PEC__LOWADDR_CPL_MASK;
if ( pecRecd[PEC__CPL_ID] != tlpHdr[PEC_PCI__CPL_ID]
|| pecRecd[PEC__CPL_STATUS] != tlpHdr[PEC_PCI__CPL_STATUS]
|| pecRecd[PEC__CPL_REQ_ID] != tlpHdr[PEC_PCI__CPL_REQ_ID]
|| pecRecd[PEC__CPL_TAG] != tlpHdr[PEC_PCI__CPL_TAG]
|| pecRecd[PEC__BCM] != tlpHdr[PEC_PCI__BCM]
|| pecRecd[PEC__BYTECOUNT] != tlpHdr[PEC_PCI__BYTECOUNT]
|| ( pecRecd[PEC__LOWADDR] & lowaddrMask )
!= ( tlpHdr[PEC_PCI__LOWADDR] & lowaddrMask & ~lowaddrZero ) )
_REPORT_ERROR( "Incorrect completion from ILU" );
"Actual: ID=%x STATUS=%x REQ=%x TAG=%x BCM=%x BCNT=%x LADDR=%x pecRecd=%h",
pecRecd[PEC__CPL_STATUS],
pecRecd[PEC__CPL_REQ_ID],
pecRecd[PEC__LOWADDR] & lowaddrMask,
"Expect: ID=%x STATUS=%x REQ=%x TAG=%x BCM=%x BCNT=%x LADDR=%x tlpHdr=%h",
tlpHdr[PEC_PCI__CPL_STATUS],
tlpHdr[PEC_PCI__CPL_REQ_ID],
tlpHdr[PEC_PCI__CPL_TAG],
tlpHdr[PEC_PCI__BYTECOUNT],
tlpHdr[PEC_PCI__LOWADDR] & lowaddrMask & ~lowaddrZero,
else if ( tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_MEM
|| tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_MEM_LK )
if ( pecRecd[PEC__REQ_ID] != tlpHdr[PEC_PCI__REQ_ID]
|| pecRecd[PEC__TLP_TAG] != tlpHdr[PEC_PCI__TLP_TAG]
|| pecRecd[PEC__FIRST_DWBE] != tlpHdr[PEC_PCI__FIRST_DWBE]
|| pecRecd[PEC__LAST_DWBE] != tlpHdr[PEC_PCI__LAST_DWBE]
|| ( pecRecd[PEC__FMT_4DW] &&
pecRecd[PEC__ADDR] != tlpHdr[PEC_PCI__ADDR] )
|| ( !pecRecd[PEC__FMT_4DW] &&
pecRecd[PEC__ADDR32] != tlpHdr[PEC_PCI__ADDR32] ) )
// Moved to end of if to allow error info to print
// _REPORT_ERROR( "Incorrect DMA memory request from ILU" );
if ( pecRecd[PEC__FMT_4DW] )
sprintf( errMsg, "Actual: pecRecd=%x \n\t ID=%x TAG=%x DWBE=%x%x ADDR=%x",
pecRecd[PEC__FIRST_DWBE],
sprintf( errMsg, "Expect: tlpHdr=%x \n\t ID=%x TAG=%x DWBE=%x%x ADDR=%x",
tlpHdr[PEC_PCI__TLP_TAG],
tlpHdr[PEC_PCI__LAST_DWBE],
tlpHdr[PEC_PCI__FIRST_DWBE],
sprintf( errMsg, "Actual: pecRecd=%x \n\t ID=%x TAG=%x DWBE=%x%x ADDR=%x",
pecRecd[PEC__FIRST_DWBE],
sprintf( errMsg, "Expect: tlpHdr=%x \n\t ID=%x TAG=%x DWBE=%x%x ADDR=%x",
tlpHdr[PEC_PCI__TLP_TAG],
tlpHdr[PEC_PCI__LAST_DWBE],
tlpHdr[PEC_PCI__FIRST_DWBE],
tlpHdr[PEC_PCI__ADDR32] );
_REPORT_ERROR( "Incorrect DMA memory request from ILU" );
else if ( (tlpHdr[PEC_PCI__TYPE] & ~PEC_PCI__TYPE_MSG_RC_MASK)
if ( pecRecd[PEC__REQ_ID] != tlpHdr[PEC_PCI__REQ_ID]
|| pecRecd[PEC__TLP_TAG] != tlpHdr[PEC_PCI__TLP_TAG]
|| pecRecd[PEC__MSG_CODE] != tlpHdr[PEC_PCI__MSG_CODE] )
sprintf( errMsg, "Actual: ID=%x TAG=%x CODE=%x pecRecd=%h",
sprintf( errMsg, "Actual: PEC__FMT=%x PEC__TYPE=%x PEC__MSG_CODE=%x",
sprintf( errMsg, "Expect: ID=%x TAG=%x CODE=%x tlpHdr=%h",
tlpHdr[PEC_PCI__TLP_TAG],
tlpHdr[PEC_PCI__MSG_CODE],
sprintf( errMsg, "Expect: PEC_PCI__FMT=%x PEC_PCI__TYPE=%x PEC_PCI__MSG_CODE=%x",
tlpHdr[PEC_PCI__MSG_CODE]
_REPORT_ERROR( "Incorrect message from ILU" );
else if ( expType == PEC__TYPE_UR )
_REPORT_ERROR( "Incorrect 'unsupported request' from ILU" );
if ( tlpHdr[PEC_PCI__FMT_4DW] )
lowAddr = tlpHdr[PEC_PCI__ADDR];
lowAddr = tlpHdr[PEC_PCI__ADDR32];
sprintf( errMsg, "Actual: ID=%x TAG=%x DWBE=%x%x ADDR=%x pecRecd=%h",
pecRecd[PEC__FIRST_DWBE],
sprintf( errMsg, "Expect: ID=%x TAG=%x DWBE=%x%x ADDR=%x tlpHdr=%h",
tlpHdr[PEC_PCI__TLP_TAG],
tlpHdr[PEC_PCI__LAST_DWBE],
tlpHdr[PEC_PCI__FIRST_DWBE],
} /* end of unsupported request check */
_REPORT_ERROR( "Internal error in 'chkPecRecd'... unexpected type" );
* sendPecRecd - Present a PEC record to the ILU
* tlpHdr - The TLP header (in PCI-Express format) to be represented
* douAddr - The starting DOU address for payload
task DMUXtr::sendPecRecd( bit[PEC_PCI__HDR] tlpHdr, bit[7:0] douAddr )
pecRecd = { urandom(), urandom(), urandom(), urandom() };
pecRecd[PEC__FMT] = tlpHdr[PEC_PCI__FMT];
pecRecd[PEC__TYPE] = tlpHdr[PEC_PCI__TYPE];
pecRecd[PEC__TC] = tlpHdr[PEC_PCI__TC];
pecRecd[PEC__ATTR] = tlpHdr[PEC_PCI__ATTR];
pecRecd[PEC__LEN] = tlpHdr[PEC_PCI__LEN];
if ( tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_CPL
|| tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_CPL_LK )
pecRecd[PEC__ADDR32] = 32'b0; // To clear bit above lowaddr
pecRecd[PEC__CPL_ID] = tlpHdr[PEC_PCI__CPL_ID];
pecRecd[PEC__CPL_STATUS] = tlpHdr[PEC_PCI__CPL_STATUS];
pecRecd[PEC__CPL_REQ_ID] = tlpHdr[PEC_PCI__CPL_REQ_ID];
pecRecd[PEC__CPL_TAG] = tlpHdr[PEC_PCI__CPL_TAG];
pecRecd[PEC__BCM] = tlpHdr[PEC_PCI__BCM];
pecRecd[PEC__BYTECOUNT] = tlpHdr[PEC_PCI__BYTECOUNT];
pecRecd[PEC__LOWADDR] = tlpHdr[PEC_PCI__LOWADDR];
pecRecd[PEC__D_PTR] = douAddr[7:2];
else if ( tlpHdr[PEC_PCI__TYPE] == PEC_PCI__TYPE_MEM ){
pecRecd[PEC__REQ_ID] = tlpHdr[PEC_PCI__REQ_ID];
pecRecd[PEC__TLP_TAG] = tlpHdr[PEC_PCI__TLP_TAG];
pecRecd[PEC__FIRST_DWBE] = tlpHdr[PEC_PCI__FIRST_DWBE];
pecRecd[PEC__LAST_DWBE] = tlpHdr[PEC_PCI__LAST_DWBE];
if ( tlpHdr[PEC_PCI__FMT_4DW] ){
pecRecd[PEC__ADDR] = tlpHdr[PEC_PCI__ADDR];
pecRecd[PEC__ADDR32] = tlpHdr[PEC_PCI__ADDR32];
if ( tlpHdr[PEC_PCI__FMT_DATA] ){
//pecRecd[PEC__D_PTR] = douAddr[7:2];
pecRecd[PEC__D_PTR] = {douAddr[7:6],douAddr[3:0]};
else /* if it's a config or I/O request... */
pecRecd[PEC__REQ_ID] = tlpHdr[PEC_PCI__REQ_ID];
pecRecd[PEC__TLP_TAG] = tlpHdr[PEC_PCI__TLP_TAG];
pecRecd[PEC__FIRST_DWBE] = tlpHdr[PEC_PCI__FIRST_DWBE];
pecRecd[PEC__LAST_DWBE] = 4'b0000;
pecRecd[PEC__ADDR32] = tlpHdr[PEC_PCI__ADDR32];
if ( tlpHdr[PEC_PCI__FMT_DATA] )
//pecRecd[PEC__D_PTR] = douAddr[7:2];
pecRecd[PEC__D_PTR] = {douAddr[7:6],douAddr[3:0]};
// - Shift data right by 2 bits since pecRecd is 126 bits and $recd is 124
egressPort.$recd <= pecRecd >> 2;
_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",
pecRecd[PEC__FIRST_DWBE] )
* fillDataOut - Put significant data into the DataOut memory
* douAddr - The starting address of the DataOut memory
* dwCount - The number of DWs of data to initialize
* payload - The byte to fill the memory with
* gasDWs - The number of DWs of garbage before the first "payload" DW
* cplData - Is this data for a DMA-read completion?
task DMUXtr::fillDataOut( bit[7:0] douAddr,
_DEBUG_MSG( psprintf("DMUXtr::DMUXtr::fillDataOut douAddr=%h dwCount=%0d payload=%0h gasDWs=%0d \n",douAddr,dwCount,payload,gasDWs) );
// Put as many DWs of "payload" into
// the "dataOut" memory as required.
for ( i=0; i<dwCount+gasDWs; i++ )
dataRow = { dataRow[95:0], 32'hBabeF00D };
// Add another DW of incrementing bytes.
// OR a DW of stuff followed by zeros
// if we're filling in the second and
// subsequent blocks of a DMA completion
if ( cplData && i >= 16 && j > 0 )
dataRow = { dataRow[119:0], 8'b00 };
dataRow = { dataRow[119:0], dataByte };
// If this row is full, then add it to
// the dataOut memory and increment
dataOutMemory[dataAddr] = dataRow;
// else if ( dataAddr == 8'hbf )
else if ( dataAddr == 8'h8f )
// If there is a partial row, then fill
// it with junk DWs and add it to the
dataRow = { dataRow[95:0], 32'hBabeF00D };
dataOutMemory[dataAddr] = dataRow;
* injectParityError - Inject a parity error into the "dataOutMemory"
* douAddr - The starting address of the DataOut memory
* gasDWs - The number of DWs of garbage before the first "payload" DW
* errMask - Which bits should get clobbered?
task DMUXtr::injectParityErr(bit[7:0] douAddr, integer gasDWs, bit[7:0] errMask)
dataOutMemoryErr[ douAddr*4 + gasDWs ] = 1'b1;
if ( errMask[i] ) dataOutMemoryErr[ douAddr*4 + gasDWs + i ] = 1'b1;
} /* end injectParityErr */
* fillCplData - Put correct data into a now-valid dataOut memory block
* douAddr - The starting address of the DataOut memory block (16 DWs)
* Each "incorrect" DW in the block has a correct high-order byte followed
* by either zeros (for "count") or ones (for "fill")
task DMUXtr::fillCplData( bit[7:0] douAddr )
dataRow = dataOutMemory[dataAddr];
if ( dataRow[23:0] == 24'h000000 )
dataRow[23:16] = dataRow[31:24] + 1;
dataRow[15:8] = dataRow[31:24] + 2;
dataRow[7:0] = dataRow[31:24] + 3;
else if ( dataRow[23:0] == 24'hffffff )
dataRow[23:16] = dataRow[31:24];
dataRow[15:8] = dataRow[31:24];
dataRow[7:0] = dataRow[31:24];
dataRow = { dataRow[95:0], dataRow[127:96] };
dataOutMemory[dataAddr] = dataRow;
* enqueueIngressData - Add an entry to the "ingressDataQueue"
* payload - The starting byte of the payload (with a high-order error bit)
* dwCount - The number of 4-byte DWs in the payload
* posted - Is the data associated with a posted DMA request?
task DMUXtr::enqueueIngressData( bit[8:0] payload,
mailbox_put( ingressDataQueue, {posted,count,payload} );
} /* end enqueueIngressData */
* dequeueIngressData - Get an entry from the "ingressDataQueue"
* payload - The starting byte of the payload
* payloadErr - Is a parity error expected?
* dwCount - The number of 4-byte DWs in the payload
* posted - Is the data associated with a posted DMA request?
task DMUXtr::dequeueIngressData( var bit[7:0] payload,
void = mailbox_get( WAIT, ingressDataQueue, dataSpec );
payloadErr = dataSpec[8];
dwCount = dataSpec[24:9];
} /* end dequeueIngressData */