Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / env / ilu_peu / vera / N2fc / N2fcCtx.vr
CommitLineData
86530b38
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: N2fcCtx.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 <vera_defines.vrh>
36#include "ccx_ncu.port_bind.vri"
37#include "plusArgMacros.vri"
38
39extern class PEUTestBase { }
40extern class N2fcPEUparams { }
41extern event e_StartPEUTest;
42
43extern integer non_posted_read_cmpl_outstanding;
44extern integer non_posted_write_cmpl_outstanding;
45
46extern reg asmDiagDone;
47
48class N2fcCtx extends PEUTestBase {
49
50 N2fcPEUparams params;
51
52 N2fcXactionProbe n2fcXactionProbe;
53
54 integer pio_mbox;
55 integer dma_mbox;
56
57 bit DtmMode;
58
59 bit env_setup;
60 integer pio_error; // 0 = no error, 1 = timeout, 2 = uc, 3 = noexp, 4 = nullify
61
62 integer dma_tc; // -1 = random, otherwise set TC to dma_tc
63
64 task new ();
65 task Wait4Asm ();
66 task Wait4Pio ();
67 virtual public task execute(); // extend N2PEUTestBase class
68
69 task Wait4Dma ();
70
71 task CfgIOAccess (string cmd,
72 bit [63:0] addr,
73 bit [31:0] length,
74 bit [63:0] data);
75
76 task MemAccess (string cmd,
77 bit [63:0] addr,
78 bit [31:0] length,
79 bit [63:0] data,
80 bit [63:0] baseaddr,
81 bit [63:0] offset);
82
83 task dmawr (string cmd,
84 bit [63:0] StartAddr,
85 bit [63:0] EndAddr,
86 string TxLen,
87 bit [31:0] NumCmds);
88
89 task dmard (string cmd,
90 bit [63:0] StartAddr,
91 bit [63:0] EndAddr,
92 string TxLen,
93 bit [31:0] NumCmds,
94 string err);
95
96 task dmacfgio (string cmd,
97 bit [63:0] StartAddr,
98 bit [63:0] EndAddr,
99 string TxLen,
100 bit [31:0] NumCmds);
101
102 task intx (string cmd,
103 bit [63:0] StartAddr,
104 bit [63:0] EndAddr,
105 string TxLen,
106 bit [31:0] NumCmds);
107
108 function bit AddrAlignmentOK (string cmd,
109 bit [63:0] addr,
110 bit [31:0] length);
111
112 function bit [3:0] getFirstDWBE (bit [63:0] addr,
113 bit [31:0] length);
114
115 function bit [3:0] getLastDWBE (bit [63:0] addr,
116 bit [31:0] length);
117
118 task unsupp_cmd (string cmd);
119
120 task CheckIfDone ();
121 function integer get_timeout ();
122}
123
124
125//------------------------------------------------------------------------------
126// "new" task. Just call the parent class' new here.
127//------------------------------------------------------------------------------
128task N2fcCtx::new () {
129 reg [31:0] seedingtmpseed = 1;
130
131 super.new ();
132
133 // seed the RNG for this object to tg_seed, so that it is the same
134 // for rtl and gatesim.
135 mGetPlusargDec(tg_seed=, seedingtmpseed);
136 srandom( seedingtmpseed );
137
138 n2fcXactionProbe = new (super.Scenario);
139
140 env_setup = 0;
141 pio_error = 0;
142 pio_mbox = alloc(MAILBOX, 0, 1);
143 dma_mbox = alloc(MAILBOX, 0, 1);
144
145 non_posted_read_cmpl_outstanding = 0;
146 non_posted_write_cmpl_outstanding = 0;
147 DtmMode = 0;
148 dma_tc = random(); // pick a random Traffic Class, to be the same for all DMAs
149
150 repeat (1) @ (posedge pcx_ncu_bind.$clk);
151
152 fork
153 Wait4Asm ();
154 Wait4Pio ();
155 Wait4Dma ();
156 join none
157}
158
159
160//------------------------------------------------------------------------------
161// "execute" task. Just call the parent class' new here.
162//------------------------------------------------------------------------------
163task N2fcCtx::execute () {
164 if (!DtmMode) {
165 super.execute ();
166 }
167
168 // env is not valid until super.execute has finished.
169 n2fcXactionProbe.setenv(env);
170 env.expectCompleteTO = get_timeout(); // scale timeout by linkwidth
171 env.setIngressGap(0,0);
172 env_setup = 1;
173 trigger( ON, env.ev_linkUp );
174}
175
176
177
178//------------------------------------------------------------------------------
179// wait4Asm method. Get parameters of the command.
180// the transaction parameters are passed from the assembly user event.
181// Decode the command and forward to the pio or dma mailboxes.
182//------------------------------------------------------------------------------
183
184task N2fcCtx::Wait4Asm () {
185 ilupeuPodClass Pod;
186 PEUTestEnv Env;
187
188 while (1) {
189 if (mailbox_get(NO_WAIT, asm2peu_mbox, params)) {
190
191 //printf ("-%0d-DEBUG N2fcCtx::Wait4Asm got a %s cmd from mbox \n", get_time(LO),params.cmdType);
192
193 case (params.cmdType) {
194 "CFGRD0", "CFGRD1", "IORD", "IOWR", "CFGWR0", "CFGWR1",
195 "MRD", "MWR", "MEM64RD", "MEM64WR",
196 "PIO_TIMEOUT", "PIO_UC", "PIO_NOEXP", "PIO_NULLIFY" :
197 mailbox_put(pio_mbox, params);
198
199 "DMAWR", "DMAWR_DWBE", "DMARD", "DMARDLK", "DMARD_UE", "DMARD_DROP",
200 "DMARD_INTA", "DMARD_INTB", "DMARD_INTC", "DMARD_INTD",
201 "INTA", "INTB", "INTC", "INTD", "MSI64", "MSI32",
202 "PM_PME", "PM_TO_ACK", "ERR_COR", "ERR_NONFATAL", "ERR_FATAL",
203 "ATTN", "VENDOR_TYPE_0", "VENDOR_TYPE_1",
204 "DMA_CFG0", "DMA_CFG1", "DMA_IO" :
205 mailbox_put(dma_mbox, params);
206
207 "LINKDOWN" : {
208 fork {
209 env.Pod.FNXPCIEEnableTrans.tempSuppressDenaliErr( PCIE_PL_NONFATAL_SYM_8B10B );
210
211 //void = DenaliDDVTclEval("mmsomaset tb_top.pcieA ttoCfgLkStartUp 2 us");
212 env.Change_soma_parameters_ac("mmsomaset tb_top.pcieA ttoCfgLkStartUp 2 us");
213
214 // force the lanes to 0, which is detected as the electical idle state
215 env.linkDown();
216 // some PIOs make come out of PEU before it recognizes the link is down
217 repeat (150*4) @(posedge pcx_ncu_bind.$clk);
218 // this will remove any pending Expects
219 env.softReset();
220 } join none
221 }
222 "SOFTRESET" : {
223 fork
224 env.softReset();
225 join none
226 }
227 "LINKUP" : {
228 // release the forces on the lanes. the link should retrain itself.
229 env.Pod.FNXPCIEEnableTrans.SetElecIdleLanes( 8'h00 );
230 trigger( ON, env.ev_linkUp );
231 }
232
233 "STARTDTM" : {
234 if (!DtmMode) {
235 // we're not using boot or InitStrategy
236 printf ("-%0d-DEBUG N2fcCtx::Wait4Asm STARTDTM (starting) \n", get_time(LO));
237 Pod = new( Report );
238 Env = new( Pod, Scenario, 4096 );
239 env = Env;
240 env.enableEnv( 0 ); // allocate semaphores and mailboxes
241 DtmMode = 1;
242
243 PiuCsrs.piuMaxPayloadSize = 512; // in DTM, MPS is forced to 512
244 printf ("-%0d-DEBUG N2fcCtx::Wait4Asm STARTDTM forced MPS to 512 \n");
245
246 trigger (ON, e_StartPEUTest); // kick fc_top.vr so it calls execute() instead of hanging
247 printf ("-%0d-DEBUG N2fcCtx::Wait4Asm STARTDTM (calling env.start_Denali_DTM) \n", get_time(LO));
248 env.start_Denali_DTM();
249 printf ("-%0d-DEBUG N2fcCtx::Wait4Asm STARTDTM (done) \n", get_time(LO));
250 }
251 }
252
253 "STALL_CPL" : {
254 printf ("\n-%0d-DEBUG N2fcCtx::Wait4Asm STALL Completions \n\n", get_time(LO));
255 trigger( OFF, env.ev_StallPioCpl);
256 //This disables Denali from returning any credits until we want it to
257 env.Pod.FNXPCIEEnableTrans.EnableFCDiscard();
258 env.expectCompleteTO = 6 * get_timeout(); // about 6x the timeout value
259 }
260
261 "UNSTALL_CPL" : {
262 printf ("\n-%0d-DEBUG N2fcCtx::Wait4Asm UNSTALL Completions \n\n", get_time(LO));
263 env.expectCompleteTO = get_timeout(); // restore the original timeout value
264 trigger( ON, env.ev_StallPioCpl);
265 fork {
266 while (non_posted_read_cmpl_outstanding + non_posted_write_cmpl_outstanding) {
267 repeat(10) @(posedge CLOCK);
268 printf ("\n-%0d-DEBUG N2fcCtx::Wait4Asm UNSTALL - NP Rds %d NP Wrts %d \n\n", get_time(LO), non_posted_read_cmpl_outstanding, non_posted_write_cmpl_outstanding);
269 }
270
271 //This turns Denali back on to be able to return credits
272 //This should only be done after you drive the completions for the PIO mem reads
273 printf ("\n-%0d-DEBUG N2fcCtx::Wait4Asm UNSTALL Disabling FC Discard \n\n", get_time(LO));
274 env.Pod.FNXPCIEEnableTrans.DisableFCDiscard();
275
276 //This turns down the Denali timer so credit updates happen quickly and
277 //then I set the timer back to a larger value
278 env.returnAllEgressCredits( 5 );
279 repeat(15) @(posedge CLOCK);
280 env.returnAllEgressCredits( 250 );
281 printf ("\n-%0d-DEBUG N2fcCtx::Wait4Asm UNSTALL Completions done \n\n", get_time(LO));
282 }
283 join none
284 }
285
286 "SET_GAP" : {
287 // set the range of cycles to wait between TLPs
288 env.setIngressGap( params.StartAddr, params.EndAddr );
289 }
290
291 "SET_TC" : {
292 // set the traffic class
293 dma_tc = params.StartAddr;
294 }
295
296 "IGNORE_PME_TURN_OFF" : {
297 // used in piu_regs_test.s
298 n2fcXactionProbe.IgnorePMETurnOff = 1;
299 }
300
301 default : unsupp_cmd (params.cmdType);
302 }
303 }
304 else {
305 @(posedge pcx_ncu_bind.$clk);
306 }
307 }
308}
309
310
311
312//------------------------------------------------------------------------------
313// wait4Pio method. Get parameters of the command.
314// the transaction parameters are passed from the assembly user event.
315// Decode the command and set appropriate fields in the Context.
316//------------------------------------------------------------------------------
317
318task N2fcCtx::Wait4Pio () {
319
320 N2fcPEUparams pioParams;
321
322 while (1) {
323 if (mailbox_get(WAIT, pio_mbox, pioParams)) {
324
325 //printf ("-%0d-DEBUG N2fcCtx::Wait4Pio got a %s cmd from mbox \n", get_time(LO),pioParams.cmdType);
326
327 case (pioParams.cmdType) {
328 "CFGRD0", "CFGRD1", "IORD", "IOWR", "CFGWR0" , "CFGWR1" :
329 CfgIOAccess (pioParams.cmdType,
330 pioParams.addr,
331 pioParams.txLen,
332 pioParams.startData);
333
334 "MRD", "MWR", "MEM64RD", "MEM64WR" :
335 MemAccess (pioParams.cmdType,
336 pioParams.addr,
337 pioParams.txLen,
338 pioParams.startData,
339 pioParams.BaseAddr,
340 pioParams.Pcie64Offset);
341 "PIO_TIMEOUT" : {
342 pio_error = 1;
343 printf ("-%0d-DEBUG N2fcCtx::Wait4Pio set the pio_error flag to 1 \n", get_time(LO));
344 }
345 "PIO_UC" : {
346 pio_error = 2;
347 printf ("-%0d-DEBUG N2fcCtx::Wait4Pio set the pio_error flag to 2 \n", get_time(LO));
348 }
349 "PIO_NOEXP" : {
350 pio_error = 3;
351 printf ("-%0d-DEBUG N2fcCtx::Wait4Pio set the pio_error flag to 3 \n", get_time(LO));
352 }
353 "PIO_NULLIFY" : {
354 pio_error = 4;
355 printf ("-%0d-DEBUG N2fcCtx::Wait4Pio set the pio_error flag to 4 \n", get_time(LO));
356 }
357
358 default : {
359 error ("\n N2fcCtx::Wait4Pio : Unknown command = %0s\n", pioParams.cmdType);
360 }
361 }
362 }
363 }
364}
365
366//------------------------------------------------------------------------------
367// Wait4Dma method. Get parameters of the command.
368// the transaction parameters are passed from the assembly user event.
369// Decode the command and set appropriate fields in the Context.
370//------------------------------------------------------------------------------
371
372task N2fcCtx::Wait4Dma () {
373
374 N2fcPEUparams dmaParams;
375
376 while (1) {
377 if (mailbox_get(WAIT, dma_mbox, dmaParams)) {
378
379 if (asmDiagDone) {
380 printf ("-%0d-DEBUG N2fcCtx::Wait4Dma: Ignoring %s cmd because assembly code is done.\n",
381 get_time(LO), dmaParams.cmdType );
382 continue;
383 }
384
385 case (dmaParams.cmdType) {
386 "DMAWR", "DMAWR_DWBE", "MSI32", "MSI64" :
387 dmawr (dmaParams.cmdType,
388 dmaParams.StartAddr,
389 dmaParams.EndAddr,
390 dmaParams.DMATxLen,
391 dmaParams.NumCmds);
392
393 "DMARD", "DMARD_UE", "DMARD_DROP", "DMARDLK",
394 "DMARD_INTA", "DMARD_INTB", "DMARD_INTC", "DMARD_INTD" :
395 dmard (dmaParams.cmdType,
396 dmaParams.StartAddr,
397 dmaParams.EndAddr,
398 dmaParams.DMATxLen,
399 dmaParams.NumCmds,
400 dmaParams.err);
401
402 "INTA", "INTB", "INTC", "INTD",
403 "PM_PME", "PM_TO_ACK", "ERR_COR", "ERR_NONFATAL", "ERR_FATAL",
404 "ATTN", "VENDOR_TYPE_0", "VENDOR_TYPE_1" :
405 intx (dmaParams.cmdType,
406 dmaParams.StartAddr,
407 dmaParams.EndAddr,
408 dmaParams.DMATxLen,
409 dmaParams.NumCmds);
410
411 "DMA_CFG0", "DMA_CFG1", "DMA_IO" :
412 dmacfgio(dmaParams.cmdType,
413 dmaParams.StartAddr,
414 dmaParams.EndAddr,
415 dmaParams.DMATxLen,
416 dmaParams.NumCmds);
417
418 default : {
419 error ("\n N2fcCtx::Wait4Dma : Unknown command = %0s\n", dmaParams.cmdType);
420 }
421 }
422 }
423 }
424}
425
426
427//------------------------------------------------------------------------------
428// CfgIOAccess method : Initiate a Config read strategy
429//------------------------------------------------------------------------------
430
431task N2fcCtx::CfgIOAccess (string cmd,
432 bit [63:0] addr,
433 bit [31:0] length,
434 bit [63:0] dat)
435{
436 N2fcPioCfgIOWrStr PioCfgWrStr;
437 N2fcPioCfgIORdStr PioCfgRdStr;
438
439 //printf ("-%0d-UDEBUG N2fcCtx::CfgIOAccess: C = %0s, A = %0h, L = %0h, D = %0h \n", get_time(LO), cmd, addr, length, dat);
440
441 void = AddrAlignmentOK (cmd, addr, length);
442
443 case (cmd) {
444 "CFGRD0", "CFGRD1", "IORD" : {
445 integer thr_perr = pio_error;
446 PioCfgRdStr = new (env, cmd, addr, length, dat, thr_perr);
447 pio_error = 0;
448 }
449
450 "CFGWR0", "CFGWR1", "IOWR": {
451 integer thr_perr = pio_error;
452 PioCfgWrStr = new (env, cmd, addr, length, dat, thr_perr);
453 pio_error = 0;
454 }
455
456 default : {
457 error ("\n N2fcCtx::CfgIOAccess : Unknown command = %0s\n", cmd);
458 }
459 }
460}
461
462
463//------------------------------------------------------------------------------
464// MemAccess method : Initiate a Memory Read or Write strategy
465//------------------------------------------------------------------------------
466
467task N2fcCtx::MemAccess (string cmd,
468 bit [63:0] addr,
469 bit [31:0] length,
470 bit [63:0] dat,
471 bit [63:0] baseaddr,
472 bit [63:0] offset)
473{
474 N2fcPioMRdStr MemRdStr;
475 N2fcPioMWrStr MemWrStr;
476
477 //printf ("-%0d-UDEBUG N2fcCtx::MemAccess: C = %0s, A = %0h, L = %0h, D = %0h O = %h\n", get_time(LO), cmd, addr, length, dat, params.Pcie64Offset);
478
479 void = AddrAlignmentOK (cmd, addr, length);
480
481 case (cmd) {
482 "MRD" : {
483 integer thr_perr = pio_error;
484 MemRdStr = new (env, cmd, addr, length, dat, baseaddr, 0, thr_perr);
485 pio_error = 0;
486 }
487
488 "MEM64RD" : {
489 integer thr_perr = pio_error;
490 MemRdStr = new (env, cmd, addr, length, dat, baseaddr, offset, thr_perr);
491 pio_error = 0;
492 }
493
494 "MWR" : {
495 integer thr_perr = pio_error;
496 MemWrStr = new (env, cmd, addr, length, dat, baseaddr, 0, thr_perr);
497 pio_error = 0;
498 }
499
500 "MEM64WR" : {
501 integer thr_perr = pio_error;
502 MemWrStr = new (env, cmd, addr, length, dat, baseaddr, offset, thr_perr);
503 pio_error = 0;
504 }
505
506 default : error ("\n N2fcCtx::MemAccess : Unknown command = %0s\n", cmd);
507 }
508}
509
510
511//------------------------------------------------------------------------------
512// dmawr method : Initiate a DMA Write
513//------------------------------------------------------------------------------
514
515task N2fcCtx::dmawr (string cmd,
516 bit [63:0] StartAddr,
517 bit [63:0] EndAddr,
518 string TxLen,
519 bit [31:0] NumCmds)
520{
521 bit [31:0] NumDMACmds;
522 for (NumDMACmds = 0; NumDMACmds < NumCmds; NumDMACmds++)
523 {
524 bit [ 9:0] DWLen;
525 integer cycles;
526
527 fork {
528 bit [63:0] RandAddr;
529 bit [63:0] data = 0;
530 integer length;
531 bit [ 1:0] Align;
532 bit [ 3:0] FirstDWBE, LastDWBE;
533 N2fcDmaWrPEUStr dmaWr = new( env );
534
535 case (cmd){
536 "MSI64" : {
537 data = StartAddr;
538 TxLen = "4";
539 dmaWr.msi_dma = 1;
540 StartAddr = PiuCsrs.piuMsi64Address;
541 EndAddr = PiuCsrs.piuMsi64Address;
542 }
543
544 "MSI32" : {
545 data = StartAddr;
546 dmaWr.msi_dma = 1;
547 TxLen = "4";
548 StartAddr = PiuCsrs.piuMsi32Address;
549 EndAddr = PiuCsrs.piuMsi32Address;
550 }
551 }
552
553 case (TxLen) {
554 "RANDOM": {
555 error ("\n N2fcCtx::dmawr : TxLen == RANDOM not supported yet\n");
556 }
557 default: {
558
559 length = TxLen.atohex();
560 if( length > super.env.getMaxPayloadSize() ) {
561 error ("\n N2fcCtx::dmawr : TxLen 0x%h > MPS\n", length);
562 }
563
564 if(cmd == "DMAWR_DWBE") {
565 if( length == 4 ) {
566 if(StartAddr[1:0]) {
567 error ("\n N2fcCtx::dmawr : Addr must be 4 byte aligned for %s\n", cmd);
568 } else {
569 Align = 0;
570 FirstDWBE = EndAddr[3:0];
571 LastDWBE = 0;
572 dmaWr.N2fcSetAddr (StartAddr, StartAddr);
573 }
574 } else if( length == 8 ) {
575 if(StartAddr[2:0]) {
576 error ("\n N2fcCtx::dmawr : Addr must be 8 byte aligned for %s\n", cmd);
577 } else {
578 Align = 0;
579 FirstDWBE = EndAddr[7:4];
580 LastDWBE = EndAddr[3:0];
581 dmaWr.N2fcSetAddr (StartAddr, StartAddr);
582 }
583 } else {
584 error ("\n N2fcCtx::dmawr : TxLen (0x%h) must be 4 or 8 for %s\n", length, cmd);
585 }
586 }
587 else if(StartAddr == EndAddr) {
588 Align = StartAddr[1:0];
589 FirstDWBE = getFirstDWBE(StartAddr,length);
590 LastDWBE = getLastDWBE(StartAddr,length);
591 dmaWr.N2fcSetAddr (StartAddr, EndAddr);
592 }
593 else {
594 // still set up DWBEs to get the byte count right
595 RandAddr[31: 0] = urandom_range (EndAddr[31:0], StartAddr[31:0]);
596 RandAddr[63:32] = urandom_range (EndAddr[63:32], StartAddr[63:32]);
597 if (({20'b0,RandAddr[11:0]} + length) > 4096) {
598 RandAddr[11:0] = 4096 - length;
599 //printf ("UDEBUG N2fcCtx::dmawr: C = %0s Adjusted RandAddr[11:0] %0h for length %h\n", cmd, RandAddr[11:0], length);
600 }
601 else {
602 //printf ("UDEBUG N2fcCtx::dmawr: C = %0s no need to adjust RandAddr[11:0] %0h for length %h\n", cmd, RandAddr[11:0], length);
603 }
604
605 if( (length+RandAddr[1:0]) > super.env.getMaxPayloadSize() ) {
606 RandAddr[1:0] = 2'b00; // align to DW boundary so MPS is not exceeded
607 }
608 dmaWr.N2fcSetAddr (RandAddr, RandAddr);
609 Align = RandAddr[1:0];
610
611 FirstDWBE = getFirstDWBE(RandAddr,length);
612 LastDWBE = getLastDWBE(RandAddr,length);
613 }
614 dmaWr.SetAddrBndy( Align );
615 // NOTE : length is in bytes, and DWLen is in DWords
616 if ((length+Align) < 4) {
617 DWLen = 1;
618 }
619 else {
620 DWLen = (length+Align+3)/4;
621 }
622 dmaWr.SetLen(DWLen);
623 dmaWr.SetFirstDWBE( {FirstDWBE[0],FirstDWBE[1],FirstDWBE[2],FirstDWBE[3]} );
624 dmaWr.SetLastDWBE( {LastDWBE[0],LastDWBE[1],LastDWBE[2],LastDWBE[3]} );
625
626 dmaWr.start_data = data;
627 dmaWr.f_tc = dma_tc;
628
629 printf ("-%0d-UDEBUG N2fcCtx::dmawr: C = %0s, A = %0h %0h, L = 'd%0d DwLen = 'd%0d FDWBE %h LDWBE %h, %d\n",
630 get_time(LO), cmd, StartAddr, EndAddr, length, DWLen, FirstDWBE, LastDWBE, NumDMACmds );
631
632 dmaWr.Execute();
633 }
634 }
635 } join none
636 repeat (1) @ (posedge if_ILU_PEU_PCIE.refclk);
637 }
638}
639
640//------------------------------------------------------------------------------
641// dmard method : Initiate a DMA Read
642//------------------------------------------------------------------------------
643
644task N2fcCtx::dmard (string cmd,
645 bit [63:0] StartAddr,
646 bit [63:0] EndAddr,
647 string TxLen,
648 bit [31:0] NumCmds,
649 string err)
650{
651 bit [31:0] NumDMACmds;
652
653 for (NumDMACmds = 0; NumDMACmds < NumCmds; NumDMACmds++)
654 {
655 fork {
656 N2fcDmaRdPEUStr dmaRd;
657
658 integer length;
659 integer DWLen;
660 bit [ 1:0] Align;
661 bit [ 3:0] FirstDWBE, LastDWBE;
662 bit [63:0] RandAddr;
663
664 case (TxLen) {
665 "RANDOM": {
666 error ("\n N2fcCtx::dmard : TxLen == RANDOM not supported yet\n");
667 }
668 default: {
669
670 dmaRd = new( env );
671
672 length = TxLen.atohex();
673 if( length > 4096 ) {
674 error ("\n N2fcCtx::dmard : TxLen 0x%h > 4096\n", length);
675 }
676
677 if(StartAddr == EndAddr) {
678 Align = StartAddr[1:0];
679 FirstDWBE = getFirstDWBE(StartAddr,length);
680 LastDWBE = getLastDWBE(StartAddr,length);
681 dmaRd.N2fcSetAddr (StartAddr, EndAddr);
682
683 if (({20'b0,StartAddr[11:0]} + length) > 4096) {
684 printf ("WARNING N2fcCtx::dmard: StartAddr[11:0] %h + length %h > 4096\n", StartAddr[11:0], length);
685 }
686 }
687 else {
688 // still set up DWBEs to get the byte count right
689 RandAddr[31: 0] = urandom_range (EndAddr[31:0], StartAddr[31:0]);
690 RandAddr[63:32] = urandom_range (EndAddr[63:32], StartAddr[63:32]);
691 if (({20'b0,RandAddr[11:0]} + length) > 4096) {
692 RandAddr[11:0] = 4096 - length;
693 printf ("UDEBUG N2fcCtx::dmard: C = %0s Adjusted RandAddr[11:0] %0h for length %h\n", cmd, RandAddr[11:0], length);
694 }
695 else {
696 printf ("UDEBUG N2fcCtx::dmard: C = %0s no need to adjust RandAddr[11:0] %0h for length %h\n", cmd, RandAddr[11:0], length);
697 }
698 dmaRd.N2fcSetAddr (RandAddr, RandAddr);
699 Align = RandAddr[1:0];
700
701 FirstDWBE = getFirstDWBE(RandAddr,length);
702 LastDWBE = getLastDWBE(RandAddr,length);
703 }
704 dmaRd.SetAddrBndy( Align );
705 // NOTE : length is in bytes, and DWLen is in DWords
706 if ((length+Align) < 4) {
707 DWLen = 1;
708 }
709 else {
710 DWLen = (length+Align+3)/4;
711 }
712 dmaRd.SetLen(DWLen);
713 dmaRd.SetFirstDWBE( {FirstDWBE[0],FirstDWBE[1],FirstDWBE[2],FirstDWBE[3]} );
714 dmaRd.SetLastDWBE( {LastDWBE[0],LastDWBE[1],LastDWBE[2],LastDWBE[3]} );
715
716 printf ("-%0d-UDEBUG N2fcCtx::dmard: C = %0s, A = %0h %0h, L = 'd%0d DwLen = 'd%0d FDWBE %h LDWBE %h err %s\n",
717 get_time(LO), cmd, StartAddr, EndAddr, length, DWLen, FirstDWBE, LastDWBE, err);
718
719 if(cmd == "DMARD_DROP")
720 dmaRd.DropCmpl();
721 else if(cmd == "DMARD_UE")
722 dmaRd.SetPoisonedPayload();
723 else if(cmd.substr(0,8) == "DMARD_INT")
724 dmaRd.DoIntxAfterCompletion( cmd.substr(6) );
725 else if(cmd == "DMARDLK")
726 dmaRd.SetRdLk();
727
728 dmaRd.f_tc = dma_tc;
729 dmaRd.Execute();
730 }
731 }
732 } join none
733 repeat (1) @ (posedge if_ILU_PEU_PCIE.refclk);
734 }
735}
736
737
738
739//------------------------------------------------------------------------------
740// dmacfgio method : Initiate a DMA Cfg/Io Read/Write (unsupported request)
741//------------------------------------------------------------------------------
742
743task N2fcCtx::dmacfgio(string cmd,
744 bit [63:0] StartAddr,
745 bit [63:0] EndAddr,
746 string TxLen,
747 bit [31:0] NumCmds)
748{
749 bit [31:0] NumDMACmds;
750
751 for (NumDMACmds = 0; NumDMACmds < NumCmds; NumDMACmds++)
752 {
753 N2fcDmaCfgIORwStr dmaCfgIoRw = new(env, cmd, StartAddr, 0 );
754
755 repeat (1) @ (posedge pcx_ncu_bind.$clk);
756 }
757}
758
759
760
761//------------------------------------------------------------------------------
762// Make sure that byte alignments are correct.
763// Otherwise drop the transaction
764//------------------------------------------------------------------------------
765
766function bit N2fcCtx::AddrAlignmentOK (string cmd,
767 bit [63:0] addr,
768 bit [31:0] length)
769{
770 integer rwLen;
771 bit rdCmd;
772
773 string methodName = "N2fcCtx::AddrAlignmentOK";
774 string errStr = "Illegal Address length Combination";
775
776
777 AddrAlignmentOK = 1'b1; // OK = 1'b1 Not OK = 1'b0
778
779 case (cmd) {
780 "CFGWR0", "CFGWR1", "IOWR", "MWR", "MEM64WR" : {
781 rwLen = length[0] + length[1]+ length[2]+ length[3] +
782 length[4]+ length[5] + length[6] + length[7];
783 rdCmd = 1'b0;
784 }
785
786 "CFGRD0", "CFGRD1", "IORD", "MRD", "MEM64RD" : {
787 rwLen = length;
788 rdCmd = 1'b1;
789 }
790
791 default :
792 error ("\n N2fcCtx::AddrAlignmentOK : Unknown command = %0s\n", cmd);
793 }
794
795
796 case (rwLen) {
797 1 : { /* Any address is OK */ }
798
799 2 : /* must be aligned to 2-byte boundary */ {
800 case (addr[0]) {
801 1'b0 : { /* OK */ }
802 default : {
803 AddrAlignmentOK = 1'b0;
804 //printf ("%0s : %0s Cmd = %0s, %0h, %0d\n", methodName, errStr, rdCmd, addr[3:0], rwLen);
805 }
806 }
807 }
808
809 4 : /* must be aligned to 4-byte boundary */ {
810 case (addr[1:0]) {
811 2'b00 : { /* OK */ }
812 default : {
813 AddrAlignmentOK = 1'b0;
814 //printf ("%0s : %0s Cmd = %0s, %0h, %0d\n", methodName, errStr, rdCmd, addr[3:0], rwLen);
815 }
816 }
817 }
818
819 8 : /* must be aligned to 8-byte boundary */ {
820 case (addr[2:0]) {
821 3'b000 : { /* OK */ }
822 default : {
823 AddrAlignmentOK = 1'b0;
824 //printf ("%0s : %0s Cmd = %0s, %0h, %0d\n", methodName, errStr, rdCmd, addr[3:0], rwLen);
825 }
826 }
827 }
828
829 16 : /* must be aligned to 16-byte boundary */ {
830 case (addr[3:0]) {
831 4'b0000 : /* OK for Read command only*/ {
832 if (rdCmd !== 1'b1) {
833 AddrAlignmentOK = 1'b0;
834 //printf ("%0s : %0s Cmd = %0s, %0h, %0d\n", methodName, errStr, rdCmd, addr[3:0], rwLen);
835 }
836 }
837 default : {
838 AddrAlignmentOK = 1'b0;
839 printf ("%0s : %0s Cmd = %0s, %0h, %0d\n", methodName, errStr, rdCmd, addr[3:0], rwLen);
840 }
841 }
842 }
843 }
844}
845
846
847//------------------------------------------------------------------------------
848// unsupp_cmd method : Unsupported PCIe command type
849//------------------------------------------------------------------------------
850
851task N2fcCtx::unsupp_cmd (string cmd)
852{
853 error ("\n This command is not currently supported : %0s\n\n", cmd);
854}
855
856
857//------------------------------------------------------------------------------
858// intx method : Initiate an INTx command
859//------------------------------------------------------------------------------
860
861task N2fcCtx::intx (string cmd,
862 bit [63:0] StartAddr, // ignored
863 bit [63:0] EndAddr, // ignored
864 string TxLen,
865 bit [31:0] NumCmds)
866{
867 integer NumINTxCmds;
868
869 printf ("\n-%0d-UDEBUG : N2fcCtx::intx %s %s - NumCmds %0d\n\n", get_time(LO), cmd, TxLen, NumCmds);
870
871 for (NumINTxCmds = 0; NumINTxCmds < NumCmds; NumINTxCmds++)
872 {
873 N2fcIntxStr intxStr = new(env, cmd, TxLen);
874
875 repeat (1) @ (posedge pcx_ncu_bind.$clk);
876 }
877}
878
879
880//------------------------------------------------------------------------------
881// getFirstDWBE function : get first DWBE for DMA
882//------------------------------------------------------------------------------
883
884function bit [3:0] N2fcCtx::getFirstDWBE (bit [63:0] addr,
885 bit [31:0] length)
886{
887 getFirstDWBE = 4'b1111;
888 if(length < 4) {
889 getFirstDWBE = (getFirstDWBE << (4-length));
890 }
891
892 case (addr & 2'h3) {
893 0: getFirstDWBE = getFirstDWBE[3:0]; // no change
894 1: getFirstDWBE = {1'b0, getFirstDWBE[3:1]};
895 2: getFirstDWBE = {2'b00, getFirstDWBE[3:2]};
896 3: getFirstDWBE = {3'b000, getFirstDWBE[3:3]};
897 }
898}
899
900
901//------------------------------------------------------------------------------
902// getLastDWBE function : get last DWBE for DMA
903//------------------------------------------------------------------------------
904
905function bit [3:0] N2fcCtx::getLastDWBE (bit [63:0] addr,
906 bit [31:0] length)
907{
908 if(((addr & 2'h3) + length) <= 4) {
909 getLastDWBE = 4'b0000;
910 }
911 else {
912 length = length - (addr & 2'h3);
913 case (length % 4) {
914 0: getLastDWBE = 4'b1111;
915 1: getLastDWBE = 4'b1110;
916 2: getLastDWBE = 4'b1100;
917 3: getLastDWBE = 4'b1000;
918 }
919 }
920}
921
922
923//------------------------------------------------------------------------------
924// CheckIfDone method : Make sure all transactions are completed.
925//------------------------------------------------------------------------------
926
927task N2fcCtx::CheckIfDone ()
928{
929 if (env_setup) {
930 env.quiesceEgressPipeline();
931 }
932}
933
934//------------------------------------------------------------------------------
935// get_timeout method : scale the timeout by the linkwidth
936//------------------------------------------------------------------------------
937
938function integer N2fcCtx::get_timeout ()
939{
940 case( Scenario.denaliLinkCapMaxLinkWdth ){
941 8: get_timeout = 8000;
942 4: get_timeout = 16000;
943 2: get_timeout = 32000;
944 1: get_timeout = 64000;
945 default: get_timeout = 8000;
946 }
947}