Commit | Line | Data |
---|---|---|
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 | ||
39 | extern class PEUTestBase { } | |
40 | extern class N2fcPEUparams { } | |
41 | extern event e_StartPEUTest; | |
42 | ||
43 | extern integer non_posted_read_cmpl_outstanding; | |
44 | extern integer non_posted_write_cmpl_outstanding; | |
45 | ||
46 | extern reg asmDiagDone; | |
47 | ||
48 | class 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 | //------------------------------------------------------------------------------ | |
128 | task 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 | //------------------------------------------------------------------------------ | |
163 | task 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 | ||
184 | task 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 | ||
318 | task 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 | ||
372 | task 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 | ||
431 | task 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 | ||
467 | task 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 | ||
515 | task 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 | ||
644 | task 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 | ||
743 | task 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 | ||
766 | function 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 | ||
851 | task 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 | ||
861 | task 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 | ||
884 | function 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 | ||
905 | function 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 | ||
927 | task 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 | ||
938 | function 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 | } |