Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / env / ilu_peu / vera / N2fc / N2fcilupeuIngressDmaWrStr.vr
CommitLineData
86530b38
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: N2fcilupeuIngressDmaWrStr.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 "l2_packet.vrh"
36#include "ios_l2_stub.vrh"
37#include "fc_top.if.vrh"
38
39extern VeraList_l2_packet l2_list0;
40extern VeraList_l2_packet l2_list1;
41extern VeraList_l2_packet l2_list2;
42extern VeraList_l2_packet l2_list3;
43extern VeraList_l2_packet l2_list4;
44extern VeraList_l2_packet l2_list5;
45extern VeraList_l2_packet l2_list6;
46extern VeraList_l2_packet l2_list7;
47extern ios_l2_stub l2_stub[];
48
49extern StandardDisplay dbg;
50
51
52class N2fcDmaWrPEUStr extends PEUStrBase {
53
54 local bit [63:0] N2fcSAddr;
55 local bit [63:0] N2fcEAddr;
56 local bit N2fcAddrSpecified;
57 local bit [31:0] length;
58 local bit [31:0] dat;
59 bit [511:0] write_data = 0;
60 bit [63:0] start_data = 0;
61 bit msi_dma = 0;
62 N2fcIommuMgr MMU;
63 bit [7:0] bus_id;
64
65 integer f_len; // The packet's payload length
66 bit[3:0] f_firstDWBE; // It's "first DWBE" field
67 bit[3:0] f_lastDWBE; // It's "last DWBE" field
68 integer f_bndy; // The address' boundary
69 bit f_lenSpecified; // Was a length specified?
70 bit f_firstSpecified; // Was a "firstDWBE" specified?
71 bit f_lastSpecified; // Was a "lastDWBE" specified?
72 bit f_bndySpecified; // Was an addr bndy specified?
73 integer f_tc; // The packet's traffic class
74
75 function bit [63:0] hashpa (bit [63:0] pa) {
76 if (probe_if.hashing && ~pa[39])
77 hashpa = {pa[63:18], pa[32:28] ^ pa[17:13], pa[19:18] ^ pa[12:11], pa[10:0]};
78 else
79 hashpa = pa;
80 }
81
82 task new( PEUTestEnv a_env) {
83 bit [3:0] index;
84
85 super.new( a_env );
86
87 if (!msi_dma){
88 if (!get_plus_arg(CHECK, "DISABLE_L2_CHECKER")) {
89 for ( index=0; index <8; index++){
90 l2_stub[index].enable_l2_checker = 1;
91 l2_stub[index].enable_l2_wr_checker = 1;
92 }
93 }
94 }
95 f_lenSpecified = 0;
96 f_firstSpecified = 0;
97 f_lastSpecified = 0;
98 f_bndySpecified = 0;
99 N2fcAddrSpecified = 0;
100 f_tc = -1;
101 MMU = new();
102
103 printf ("%0d- N2fcDmaWrPEUStr:new first random # = %0h\n", get_time(LO), random() );
104 }
105
106 task SetLen( integer a_len )
107 {
108 f_len = a_len;
109 f_lenSpecified = 1;
110 }
111 task SetFirstDWBE( bit[3:0] a_dwbe )
112 {
113 f_firstDWBE = a_dwbe;
114 f_firstSpecified = 1;
115 }
116 task SetLastDWBE( bit[3:0] a_dwbe )
117 {
118 f_lastDWBE = a_dwbe;
119 f_lastSpecified = 1;
120 }
121 task SetAddrBndy( integer a_bndy )
122 {
123 f_bndy = a_bndy;
124 f_bndySpecified = 1;
125 }
126
127 task N2fcSetAddr( bit [63:0] i_saddr, bit [63:0] i_eaddr )
128 {
129 N2fcAddrSpecified = 1;
130 N2fcSAddr = i_saddr;
131 N2fcEAddr = i_eaddr;
132 }
133
134//-------------------------------------------------------------------
135// Method Name:
136// Description:
137//-------------------------------------------------------------------
138 function bit[31:0] gen_4bytes_exp_data (bit [31:0] data, bit [3:0] bytemask){
139 integer index;
140
141 for (index =0; index < 4; index++){
142 if (bytemask[3-index]) {
143 gen_4bytes_exp_data[31-8*index:32-8*(index+1)] = data[31-8*index:32-8*(index+1)];
144 } else {
145 gen_4bytes_exp_data[31-8*index:32-8*(index+1)] = 8'hx;
146 }
147 }
148 }
149
150//-------------------------------------------------------------------
151// Method Name:
152// Description:
153//-------------------------------------------------------------------
154 task gen_exp_l2_pkt8bytes(
155 bit [31:0] dma_dword_len,
156 var bit [63:0] address,
157 bit bypass_first_word,
158 bit bypass_last_word,
159 var integer ingressData,
160 bit [7:0] ingressTag
161 ){
162 integer i, j;
163 bit [7:0] bytemask;
164 l2_packet l2_pkt = new("L2Expect", dbg);
165 bit last_packet = 0;
166 bit [2:0] bank_number;
167 reg [3:0] pbank = {probe_if.ba67, probe_if.ba45, probe_if.ba23, probe_if.ba01};
168 integer index;
169 write_data = 0;
170 for (j = 0; j < dma_dword_len; j++) {
171 bit [31:0] tmp_data;
172
173
174 if (j==0 && address[2]){
175 index = 1;
176 } else if (j == 0 ){
177 index = 0;
178 }
179 if (index%2 == 0){
180 bytemask = 8'hff;
181 }
182 tmp_data = f_env.nextPayloadDW( ingressData );
183
184 if (j == 0 && !bypass_first_word){ // modify for first words
185 if (address[2]){
186 bytemask [3:0] = {f_firstDWBE[0],f_firstDWBE[1],f_firstDWBE[2],f_firstDWBE[3]};
187 bytemask [7:4] = 0;
188 } else {
189 bytemask [7:4] = {f_firstDWBE[0],f_firstDWBE[1],f_firstDWBE[2],f_firstDWBE[3]};
190 if (dma_dword_len == 1){
191 bytemask [3:0] = 0;
192 }
193 }
194 } else if (j == dma_dword_len-1 && !bypass_last_word){ // modify for last words
195 if (address[2]){
196 // bytemask[7:4] = 0;
197 bytemask[3:0] = {f_lastDWBE[0], f_lastDWBE[1], f_lastDWBE[2], f_lastDWBE[3]};
198 } else {
199 bytemask[7:4] = {f_lastDWBE[0], f_lastDWBE[1], f_lastDWBE[2], f_lastDWBE[3]};
200 bytemask [3:0] = 0;
201 }
202 }
203
204
205 if (index%2 == 0){
206 write_data[63:32] = gen_4bytes_exp_data(tmp_data, bytemask[7:4]);
207 if (j == dma_dword_len-1){
208 write_data[31:0] = gen_4bytes_exp_data(tmp_data, bytemask[3:0]);
209 }
210 } else {
211 write_data[31:0] = gen_4bytes_exp_data(tmp_data, bytemask[3:0]);
212 if (j == 0 ){
213 write_data[63:32] = gen_4bytes_exp_data(tmp_data, bytemask[7:4]);
214
215 }
216 }
217
218 last_packet = ((j == dma_dword_len - 1) || (address[5:2] == 4'b1111));
219
220 if(index%2 == 1 || j == dma_dword_len -1 ){
221
222 l2_pkt.set("tag", ingressTag);
223 l2_pkt.set("address", hashpa({address[63:3], 3'h0}) );
224 l2_pkt.set("data", write_data);
225 l2_pkt.set("bytemask", bytemask);
226 l2_pkt.set("opes", 4'b1101);
227 // printf("last_packet is %0b", last_packet);
228 l2_pkt.set("last_packet", last_packet);
229 //bank_number = address[8:6];
230 bank_number = address[8:6];
231 if (probe_if.pm === 1'b1)
232 bank_number = pbank_sel(pbank, bank_number);
233
234 l2_pkt.set("bank_number", bank_number);
235 l2_pkt.display("Putting a packet on the L2 Expect Queue");
236 case (bank_number) {
237 0: l2_list0.push_back(l2_pkt.copy());
238 1: l2_list1.push_back(l2_pkt.copy());
239 2: l2_list2.push_back(l2_pkt.copy());
240 3: l2_list3.push_back(l2_pkt.copy());
241 4: l2_list4.push_back(l2_pkt.copy());
242 5: l2_list5.push_back(l2_pkt.copy());
243 6: l2_list6.push_back(l2_pkt.copy());
244 7: l2_list7.push_back(l2_pkt.copy());
245 }
246 }
247 address = address + 4;
248 index++;
249 }
250 }
251
252//-------------------------------------------------------------------
253// Method Name:
254// Description:
255//-------------------------------------------------------------------
256 task Execute()
257 {
258 bit [63:0] address = 64'b0; // Virtual address
259 bit [39:0] pa = 40'b0; // Physical address
260 bit [63:0] response = 64'b0;
261 bit [5:0] start_add;
262
263 l2_packet l2_pkt;
264
265 bit [7:0] bytemask;
266 bit [2:0] bank_number;
267
268 bit last_packet;
269
270 bit[PEC_PCI__HDR] ingressHdr; // The ingress TLP's header
271 integer ingressData; // A payload descriptor
272 bit[7:0] ingressTag; // The tag for the TLP
273 reg [3:0] pbank = {probe_if.ba67, probe_if.ba45, probe_if.ba23, probe_if.ba01};
274
275 if (N2fcAddrSpecified == 1) {
276 address = N2fcSAddr;
277 }
278 else {
279 error ("N2fcDmaWrPEUStr::Execute() : the start and end address must be specifed\n");
280 }
281
282 // First, get in line for a DMA tag...
283 f_env.allocDmaTag( ingressTag );
284
285 // Then build a TLP
286 if ( f_lenSpecified )
287 f_env.genIngressWrReq( ingressTag, ingressHdr, ingressData, f_len );
288 else
289 error ("N2fcDmaWrPEUStr::Execute() : the length must be specifed\n");
290
291 if( address[63:32] != 32'h00000000 ) {
292 ingressHdr[PEC_PCI__FMT_4DW] = 1; // 4DW hdr fmt, 64-bit address
293 ingressHdr[PEC_PCI__ADDR] = address;
294 }
295 else {
296 ingressHdr[PEC_PCI__FMT_4DW] = 0; // 3DW hdr fmt, 32-bit address
297 ingressHdr[PEC_PCI__ADDR32] = address[31:0];
298 }
299
300 // set the Traffic Class
301 if( f_tc != -1 ) {
302 ingressHdr[PEC_PCI__TC] = f_tc;
303 }
304
305 printf ("%0d- UDEBUG N2fcDmaWrPEUStr:Execute Address = %0h Byp = %0h, Len = 'd%0d\n",
306 get_time(LO), address, address[63:39], f_len);
307
308 // ...and set fields as requested
309 // by the caller.
310
311 if ( f_bndySpecified )
312 f_env.setAddrBndy( ingressHdr, f_bndy, 4 );
313
314 if ( f_firstSpecified )
315 ingressHdr[PEC_PCI__FIRST_DWBE] = f_firstDWBE;
316 if ( f_lastSpecified )
317 ingressHdr[PEC_PCI__LAST_DWBE] = f_lastDWBE;
318
319// add for MSI data
320 if (msi_dma) {
321 ingressData = start_data;
322 }
323// add for MSI data
324
325
326 f_env.drivePCIE( ingressHdr, ingressData, *,*,*,*,*,1 );
327
328 bus_id = ingressHdr[ILUPEU_TLP_HDR_REQ_BUS_NUM_BITS];
329 if (msi_dma) {
330 gen_msi_exp_data(address, ingressData, ingressTag, ingressHdr[PEC_PCI__REQ_ID]);
331 }
332 else if ((f_len > 1) ||
333 ((f_len == 1) && ingressHdr[PEC_PCI__FIRST_DWBE])) {
334 integer index;
335 bit bypass_first_word = 0;
336 bit do_cache_line;
337
338 l2_pkt = new("L2Expect", dbg);
339
340 if (MMU.get_physical_address(address, pa, bus_id, 1)) {
341 address = pa; // use the physical address from here on
342 }
343 else {
344 printf("N2fcDmaWrPEUStr:Execute problem found during translation, so no L2 expects will be setup.\n");
345 return;
346 }
347
348 start_add = address[5:0] ;
349
350 if ((f_len >(64-start_add+3)/4 ) && (start_add !==0)){
351 gen_exp_l2_pkt8bytes((64-start_add+3)/4, address, 0,1, ingressData,ingressTag);
352
353 bypass_first_word = 1;
354 f_len = f_len - (64-start_add+3)/4 ;
355 address[5:0] = 0;
356 } // align to catch line start address
357
358
359 if (f_len > 16 && (address[5:0] == 0)){
360 do_cache_line =1;
361 } else if (f_len === 16 && (address[5:0] == 0)){
362 if (&f_lastDWBE){
363 do_cache_line = 1;
364 } else {
365 do_cache_line = 0;
366 }
367 } else {
368 do_cache_line = 0;
369 }
370
371 while (do_cache_line){ // f_len is dword length
372 bytemask = 8'h0;
373 write_data = 0;
374 for (index=0; index <64/4; index++){
375 write_data[511-32*index:512-32*(index+1)] = f_env.nextPayloadDW( ingressData );
376
377 }
378 //last_packet = (f_len == 64/4);
379 last_packet = 1;
380
381 l2_pkt.set("tag", ingressTag);
382 l2_pkt.set("address", hashpa(address) );
383 l2_pkt.set("data", write_data);
384 l2_pkt.set("bytemask", bytemask);
385 l2_pkt.set("opes", 4'b1101);
386 //printf("last_packet is %0b", last_packet);
387 l2_pkt.set("last_packet", last_packet);
388 bank_number = address[8:6];
389 if (probe_if.pm === 1'b1)
390 bank_number = pbank_sel(pbank, bank_number);
391 l2_pkt.set("bank_number", bank_number);
392 l2_pkt.display("Putting catch line packet on the L2 Expect Queue");
393 case (bank_number) {
394 0: l2_list0.push_back(l2_pkt.copy());
395 1: l2_list1.push_back(l2_pkt.copy());
396 2: l2_list2.push_back(l2_pkt.copy());
397 3: l2_list3.push_back(l2_pkt.copy());
398 4: l2_list4.push_back(l2_pkt.copy());
399 5: l2_list5.push_back(l2_pkt.copy());
400 6: l2_list6.push_back(l2_pkt.copy());
401 7: l2_list7.push_back(l2_pkt.copy());
402 }
403 address = address + 64;
404 response = response + 64;
405 f_len = f_len - 64/4;
406 if (f_len > 16 && (address[5:0] == 0)){
407 do_cache_line =1;
408 } else if (f_len === 16 && (address[5:0] == 0)){
409 if (&f_lastDWBE){
410 do_cache_line = 1;
411 } else {
412 do_cache_line = 0;
413 }
414 } else {
415 do_cache_line = 0;
416 }
417
418
419 bypass_first_word = 1;
420 }
421 if (f_len >0) {
422 gen_exp_l2_pkt8bytes(f_len, address, bypass_first_word,0,ingressData,ingressTag);
423 }
424 }
425
426 f_env.freeDmaTag( ingressTag );
427
428 } /* end Execute */
429
430//-------------------------------------------------------------------
431// Method Name: pbank_sel
432// Description: Calculate the bank number based on the partial bank
433// controls.
434//-------------------------------------------------------------------
435 function reg[2:0] pbank_sel(reg[3:0] pbank, reg[2:0] bank_sel)
436 {
437 reg [2:0] result = bank_sel;
438
439 case (pbank) {
440 4'b0001: result[2:1] = 2'b00;
441 4'b0010: result[2:1] = 2'b01;
442 4'b0011: result[2] = 1'b0;
443 4'b0100: result[2:1] = 2'b10;
444 4'b0101: result[2:1] = {bank_sel[1], 1'b0};
445 4'b0110: result[2:1] = {bank_sel[1], ~bank_sel[1]};
446 4'b1000: result[2:1] = 2'b11;
447 4'b1001: result[2:1] = {bank_sel[1], bank_sel[1]};
448 4'b1010: result[2:1] = {bank_sel[1], 1'b1};
449 4'b1100: result[2:1] = {1'b1, bank_sel[1]};
450 4'b1111: result = bank_sel;
451 default:
452 error ("ERROR! illegal partial bank selection: %0b\n", pbank);
453 }
454
455 pbank_sel = result;
456 }
457
458//-------------------------------------------------------------------
459// Method Name: gen_msi_exp_data
460// Description: Generate the expected L2 write packet for an MSI msg.
461//-------------------------------------------------------------------
462 task gen_msi_exp_data (bit [63:0] msiaddress,
463 bit [31:0] msidata,
464 bit [ 7:0] ingressTag,
465 bit [15:0] rid)
466 {
467 integer MSI_num = msidata[7:0];
468 integer EQ_num;
469 bit [63:0] address;
470 bit [39:0] pa = 40'b0; // Physical address
471 bit [63:0] word0, word1;
472 bit [7:0] bytemask = 0;
473 bit [2:0] bank_number;
474 reg [3:0] pbank = {probe_if.ba67, probe_if.ba45, probe_if.ba23, probe_if.ba01};
475 bit [6:0] tmpEQTail;
476
477 l2_packet l2_pkt;
478
479 // Figure out if the MSI is mapped
480 if( !PiuCsrs.MsiIsValid(MSI_num) ) return;
481
482 // If an MSI has been sent to the EQ, but not cleared,
483 // we can't do it again
484 if( PiuCsrs.MsiIsEqWr(MSI_num) ) return;
485 EQ_num = PiuCsrs.GetMsiEqNum(MSI_num);
486
487 //if( PiuCsrs.EQBaseAddr[63:39] != 25'b1111_1111_1111_1100_0000_0000_0) {
488 // error("ERROR: N2fcDmaWrPEUStr::gen_msi_exp_data - a non-bypass EQ BASE address is not supported!");
489 //}
490
491 // check if the EQ table is full
492 tmpEQTail = PiuCsrs.EQTail[EQ_num] + 1;
493 if (tmpEQTail == PiuCsrs.EQHead[EQ_num]) {
494 printf("Not writting to EQ[%d] for MSI %d because it is full\n", EQ_num, MSI_num);
495 return;
496 }
497
498 // all seems well ...
499 address = PiuCsrs.EQBaseAddr[63:0] + (EQ_num * 8*1024) + (PiuCsrs.EQTail[EQ_num] * 64);
500
501 MMU.set_msi(1);
502 if (MMU.get_physical_address(address, pa, bus_id, 1)) {
503 address = pa; // use the physical address from here on
504 }
505 else {
506 printf("N2fcDmaWrPEUStr:gen_msi_exp_data problem found during translation, so no L2 expects will be setup.\n");
507 MMU.set_msi(0);
508 return;
509 }
510 MMU.set_msi(0);
511
512 PiuCsrs.SetMsiEqWr(MSI_num);
513 PiuCsrs.EQTail[EQ_num]++;
514
515 // set up the msi data that will be sent
516 msidata[15: 8] = msidata[7:0] + 1;
517 msidata[23:16] = msidata[7:0] + 2;
518 msidata[31:24] = msidata[7:0] + 3;
519
520 // set up expected data (from table 16-19 of the PRM)
521 word0[63] = 0;
522 word0[62:56] = (msiaddress[63:32]==0) ? 7'b1011000 : 7'b1111000; // FMT/TYPE
523 word0[55:46] = 1; // LENGTH in DW
524 word0[45:32] = msiaddress[15:2]; // ADDR[15:2]
525 word0[31:16] = rid; word0[15: 0] = msidata[15:0]; // DATA
526
527 word1[63:16] = msiaddress[63:16]; // ADDR[63:16]
528 word1[15: 0] = msidata[31:16]; // DATA
529
530 write_data[511-64*0:512-64*1] = word0;
531 write_data[511-64*1:512-64*2] = word1;
532 write_data[511-64*2:512-64*3] = 0;
533 write_data[511-64*3:512-64*4] = 0;
534 write_data[511-64*4:512-64*5] = 0;
535 write_data[511-64*5:512-64*6] = 0;
536 write_data[511-64*6:512-64*7] = 0;
537 write_data[511-64*7:512-64*8] = 0;
538
539 l2_pkt = new("L2Expect", dbg);
540
541 l2_pkt.set("tag", ingressTag);
542 l2_pkt.set("address", hashpa(address) );
543 l2_pkt.set("data", write_data);
544 l2_pkt.set("bytemask", bytemask);
545 l2_pkt.set("opes", 4'b1101);
546 l2_pkt.set("last_packet", 1);
547 bank_number = address[8:6];
548 if (probe_if.pm === 1'b1)
549 bank_number = pbank_sel(pbank, bank_number);
550 l2_pkt.set("bank_number", bank_number);
551 l2_pkt.display("Putting cache line packet on the L2 Expect Queue");
552 case (bank_number) {
553 0: l2_list0.push_back(l2_pkt.copy());
554 1: l2_list1.push_back(l2_pkt.copy());
555 2: l2_list2.push_back(l2_pkt.copy());
556 3: l2_list3.push_back(l2_pkt.copy());
557 4: l2_list4.push_back(l2_pkt.copy());
558 5: l2_list5.push_back(l2_pkt.copy());
559 6: l2_list6.push_back(l2_pkt.copy());
560 7: l2_list7.push_back(l2_pkt.copy());
561 }
562
563 }
564
565}