Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / env / common / vera / ccxDevices / ccxDevMemBFM.vr
CommitLineData
86530b38
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: ccxDevMemBFM.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
37// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
38// To use this class, you must have in your bench a files called globals.vri
39// that has all global extern declerations in it.
40#include <globals.vri>
41
42#include <ccxDevicesDefines.vri>
43#include <cmp.vri>
44#include <std_display_defines.vri>
45
46#include <std_display_class.vrh>
47#include <basePktClass.vrh>
48#include <cpxPktClass.vrh>
49#include <pcxPktClass.vrh>
50#include <baseParamsClass.vrh>
51#include <sparcParams.vrh>
52#include <ccxDevBaseBFM.vrh>
53#include <memArray.vrh>
54#include <baseUtilsClass.vrh>
55#include <sparcBenchUtils.vrh>
56#include <ccx_tag_class.vrh>
57
58// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
59// To use this class, you must have in your bench a class that extends
60// sparcBenchUtils.vr. It must be in files named utilsClass.vr/utilsClass.vrh
61// AND have a global handle called gUtil.
62#include <utilsClass.vrh>
63
64// uncomment to debug
65//#define CCXDEVMEMBFM_DEBUG
66
67
68// #define MON_CCXPKT 24
69// #define GNT_ATTEMPTS 20
70
71#define CLASSNAME CcxDevMemBFM
72#define CLASSNAMEQ "CcxDevMemBFM"
73
74class CLASSNAME extends CcxDevBaseBFM {
75
76 local reg [63:0] cas1Data[64], cas1Addr[64];
77 local reg cas_swap [64];
78// local reg [31:0] invVectorCAS;
79 local reg cacheOff = 0;
80 local integer reqId;
81 local integer ldstSyncLock;
82 local integer stalling;
83 static reg burstSync;
84
85 // methods
86 task new(integer instatnce, reg passiveIn=0,
87 reg cacheoff = 0, reg flagUnexpected=0, reg ccxOnly=0);
88
89 // virtual in base
90 task recv(BasePkt pktHndl);
91 task cancelRecv(BasePkt pktHndl);
92
93 local task slave();
94 local task respond(PcxPkt reqPkt);
95// local task monitor();
96 local function reg [3:0] lineState(PcxPkt reqPkt,
97 string why="debug lineState:",
98 reg quiet=1);
99
100 task sendIntr(reg [5:0] tid,
101 reg [1:0] type,
102 reg [5:0] vect);
103
104 local task updateItag(PcxPkt reqPkt, CpxPkt rspPkt, CpxPkt rspPkt2 = null,
105 reg [2:0] cpuId, integer how = TAG_VAL);
106 local task updateDtag(PcxPkt reqPkt, CpxPkt rspPkt,
107 reg [2:0] cpuId, integer how = TAG_VAL);
108 local function reg data_equal(reg [63:0] data1,
109 reg [63:0] data2,
110 reg[7:0] size);
111// local task create_vector(reg table, reg [3:0] way,
112// var reg [31:0] vect, reg [2:0] core_num);
113 local function reg [31:0] getInvalVector(integer type,
114 PcxPkt reqPkt,
115 reg [2:0] cpuId);
116
117 local task ldstSync(reg [2:0] cpuId, CpxPkt rspPkt);
118 public task enqueueEvict(reg [7:0] coreEnable,
119 reg [39:0] evictPA = 40'hffffffffff,
120 reg [3:0] cid = 4'hf,
121 reg all_cores = 0,
122 integer dCacheWeight = 60);
123
124 local task burstResp(integer amount);
125
126}
127
128
129task CLASSNAME::new(integer instatnce, reg passiveIn=0,
130 reg cacheoff = 0, reg flagUnexpected=0, reg ccxOnly=0) {
131
132 super.new(instatnce, passiveIn, CLASSNAMEQ);
133 super.ccxOnly = ccxOnly; // only testing ccx
134 super.flagUnexpected = flagUnexpected;
135 srandom(gSeed,this);
136
137 cacheOff = cacheoff;
138 stalling = 0;
139 reqId = 0;
140 burstSync = 0;
141 ldstSyncLock = alloc( SEMAPHORE, 0, 1, 1 ); // this may not be needed anymore
142
143 // in base
144 super.stallStart = gParam.stallStart;
145 super.stallStop = gParam.stallStop;
146
147 if (myPort == DEV_NCU) lineHash[0] = 0;
148
149 if (!passiveIn) {
150 // Initialize Outputs
151 gPcxPort[myPort].$stall <= 0;
152 gCpxPort[myPort].$req <= 0;
153// gCpxPort[myPort].$datao <= 0;
154 if (myPort !== DEV_NCU) gCpxPort[myPort].$atmo <= 0;
155 }
156
157 fork {
158 @(posedge gPcxPort[myPort].$clk);
159 gCpxPort[myPort].$gnt == 0;
160 gPcxPort[myPort].$rdy == 0;
161 gPcxPort[myPort].$datai == 0;
162 if (myPort !== DEV_NCU) gPcxPort[myPort].$atmi == 0;
163 } join none
164
165 fork slave();
166 join none
167
168 // service mailboxes, send packets
169 fork super.serviceSends2(PP_CPX);
170 join none
171
172 if (gParam.burstAmount) {
173 fork burstResp(gParam.burstAmount);
174 join none
175 }
176
177}
178
179
180
181// Wait for data from PCX, we are a cache/IO BFM
182task CLASSNAME::slave() {
183
184 ccxPort portVar = gPcxPort[myPort];
185 reg [145:0] tmpVec;
186
187 if (!passive) {
188
189 fork
190 { // wait for packets.
191 // we can get back to back packets...
192 while (1) {
193
194 if (!portVar.$rdy) {
195 @(portVar.$rdy);
196 }
197
198 if (portVar.$rdy && stalling) {
199 error("ERROR FAIL: should not get rdy when stalled\n");
200 }
201
202 { // keep block! {}
203 PcxPkt reqPkt = new();
204 // need to fork to handle back to back reqs
205 // and delayed responses
206 fork {
207 outstandingReqs++;
208 reqPkt.ccxSourced = 1;
209 @(negedge portVar.$clk);
210 reqPkt.loadPkt(portVar.$datai, myPort);
211
212 // if on L2 port, look at portVar.$atmi and save value
213 if (myPort !== DEV_NCU) reqPkt.atm_wire = portVar.$atmi;
214
215#ifdef CCXDEVMEMBFM_DEBUG
216 printf("%0d: CcxDevMemBFM[%2d]::slave: got req packet, outstandingReqs++=%0d, atm=%0d, ccxSourced=%0d, vec=%h\n",get_time(LO),myPort,outstandingReqs,reqPkt.atm_wire,reqPkt.ccxSourced,reqPkt.getVector());
217#endif
218
219 // for CCX testing, anyone waiting for this packet?
220 // was it expected? should we auto respond?
221 if (ccxOnly) {
222 tmpVec = reqPkt.makeSignature();
223 if (assoc_index(CHECK, expectedSig, tmpVec)) {
224 expectedSig[tmpVec].loadPkt(reqPkt.getVector(), myPort);
225 expectedSig[tmpVec].arrivalTime = get_cycle();
226 expectedSig[tmpVec].pktArrived = ~expectedSig[tmpVec].pktArrived;
227 } else if (flagUnexpected) {
228 reqPkt.print(myPort);
229 PR_ERROR(CLASSNAMEQ, MON_ERROR,
230 psprintf ("Unexpected packet on port %0d, vector=%h",
231 myPort,reqPkt.getVector()));
232 }
233 } else {
234 // check how/if we should respond and do it
235 suspend_thread(); // do as last thing in this time slot.
236 if (!ccxOnly && reqPkt.valid) {
237 fork respond(reqPkt);
238 join none
239 } else {
240 // drop this packet
241 outstandingReqs--;
242 printf("%0d: CcxDevMemBFM[%2d]::slave: got invalid req packet, outstandingReqs++=%0d, atm=%0d, ccxSourced=%0d, vec=%h\n",get_time(LO),myPort,outstandingReqs,reqPkt.atm_wire,reqPkt.ccxSourced,reqPkt.getVector());
243 reqPkt.print(myPort);
244 reqPkt = null;
245 }
246 }
247
248 } join none
249 }
250
251 @(negedge portVar.$clk);
252
253 } // while
254 }
255
256
257 { // stall signal management
258 while (1) {
259 wait_var(outstandingReqs);
260 //printf("%0d: wait_var at stall check outstandingReqs=%0d\n", get_time(LO), outstandingReqs);
261 // stall? Takes 3 clocks for the CCX to actually stall
262 if (outstandingReqs >= stallStart && !stalling) {
263 fork {
264 portVar.$stall = 1;
265 //printf("%0d: CcxDevMemBFM[%2d]::stalling, outstandingReqs=%0d\n", get_time(LO),myPort, outstandingReqs);
266 repeat (2) @(negedge portVar.$clk);
267 stalling = 1;
268 } join none
269 }
270 if (outstandingReqs <= stallStop && stalling) {
271 fork {
272 portVar.$stall = 0;
273 @(negedge portVar.$clk);
274 stalling = 0;
275 //printf("%0d: CcxDevMemBFM[%2d]::un-stalling, outstandingReqs=%0d\n", get_time(LO),myPort, outstandingReqs);
276 @(negedge portVar.$clk);
277 stalling = 0; // yes, twice, in case we started stalling above
278 //printf("%0d: CcxDevMemBFM[%2d]::done un-stalling, outstandingReqs=%0d\n", get_time(LO),myPort, outstandingReqs);
279 } join none
280 }
281
282 }
283 }
284 join all
285
286 } // ! passive
287}
288
289
290task CLASSNAME::sendIntr(reg [5:0] tid,
291 reg [1:0] type,
292 reg [5:0] vect)
293{
294 CpxPkt reqPkt;
295
296 reqPkt = new();
297 reqPkt.createIntr(tid,type,vect); // INTR_RESET,INTR_POR
298 reqPkt.sendPorts = 1 << myPort;
299 reqPkt.targetPorts = 1 << tid[5:3]; // not multicast
300 reqPkt.send(1);
301}
302
303
304
305// check how/if we should respond and do it.
306// check response signature and use user response if hit (review)
307// else return a built in response.
308task CLASSNAME::respond(PcxPkt reqPkt) {
309
310 CpxPkt rspPkt, rspPkt2, rspPkt3;
311 reg [7:0] cas1size, targetCores;
312 reg [127:0] tmpData;
313 reg [31:0] invVector = 0;
314 reg [31:0] tmpInvVect = 0;
315 reg [1:0] invField = 0;
316 reg [63:0] tmp64;
317 integer i;
318 reg [5:0] thread;
319 ccxPort portVar = gCpxPort[myPort];
320 reg [63:0] tmpAddr;
321 reg [39:0] tmpPa;
322
323 // do not drive on this port
324 if (passive) return;
325
326 thread = {reqPkt.cpuId,reqPkt.tid};
327
328 // check response signature & use user pkt if hit
329 // else return built in response pkt based on request pkt fields.
330 // use fast resp mailbox.
331
332 // Some may be illegal for L2 port, check port number and address!
333 if (myPort !== DEV_NCU && reqPkt.addr[39] == 1 &&
334 (reqPkt.addr[39:32] < 8'hA0 || reqPkt.addr[39:32] > 8'hBF)) {
335 reqPkt.print(myPort);
336 PR_ERROR (CLASSNAMEQ, MON_ERR,
337 psprintf ("T%d Port=%0d request type [128:124]=%b. ERROR FAIL: Illegal I/O on non-NCU port!",thread,myPort,reqPkt.rqtyp));
338 return;
339 }
340
341 // create response packets
342 rspPkt = new(reqPkt);
343 rspPkt.sendPorts = 1 << myPort;
344 rspPkt.addr = reqPkt.addr;
345
346#ifdef CCXDEVMEMBFM_DEBUG
347 reqPkt.reqId = reqId;
348 rspPkt.reqId = reqId;
349 reqId++;
350 if (reqId == 10000) reqId = 0;
351 reqPkt.reqTime = get_time(LO);
352 rspPkt.reqTime = reqPkt.reqTime;
353 // state of tag for line at this time
354 reqPkt.lineWay = lineState(reqPkt, *, 1);
355 reqPkt.print(myPort);
356#endif
357
358 // pick a response
359 case (reqPkt.rqtyp) {
360 PCX_LD,
361 PCX_PREF,
362 PCX_PREF_ICE,
363 PCX_DIAG_LD,
364 PCX_D_INVAL:
365 {
366 case ({reqPkt.inv,reqPkt.pf}) {
367 0: {
368 if (myPort !== DEV_NCU) {
369 // can't tell diag load from load so both are load!
370 rspPkt.rtntyp = CPX_LD; // code is done
371 rspPkt.rtntypU = U_CPX_LD;
372 } else {
373 // can't tell diag load from load so both are load!
374 rspPkt.rtntyp = CPX_NCU_LD; // code is done
375 rspPkt.rtntypU = U_CPX_NCU_LD;
376 }
377 }
378 1: {
379 if (reqPkt.nc) {
380 rspPkt.rtntyp = CPX_PREF;
381 rspPkt.rtntypU = U_CPX_PREF;
382 } else {
383 error("");
384 }
385 }
386 2: {
387 if (!reqPkt.nc) {
388 rspPkt.rtntyp = CPX_D_INVAL;
389 rspPkt.rtntypU = U_CPX_D_INVAL;
390 invField = D_INVAL;
391 } else {
392 error("");
393 }
394 }
395 3: {
396 if (reqPkt.nc) {
397 rspPkt.rtntyp = CPX_PREF_ICE;
398 rspPkt.rtntypU = U_CPX_PREF_ICE;
399 } else {
400 error("");
401 }
402
403 }
404 } // case
405 } // case
406
407 PCX_ST,
408 PCX_BLK_ST,
409 PCX_BLK_INIT_ST,
410 PCX_DIAG_ST : {
411 if (reqPkt.l1wayBis && !reqPkt.pf) {
412 rspPkt.rtntyp = CPX_ST; // code is done
413 rspPkt.rtntypU = U_CPX_BIS;
414 } else if (reqPkt.l1wayBis && reqPkt.pf) {
415 rspPkt.rtntyp = CPX_ST; // code is done
416 rspPkt.rtntypU = U_CPX_BLK_ST;
417 } else {
418 // can't tell diag store from store so both are store!
419 rspPkt.rtntyp = CPX_ST; // code is done
420 rspPkt.rtntypU = U_CPX_ST;
421 }
422 }
423
424 PCX_CAS1: {
425 rspPkt.rtntyp = CPX_CAS_RTN;
426 rspPkt.rtntypU = U_CPX_CAS_RTN;
427 }
428
429 PCX_CAS2: {
430 rspPkt.rtntyp = CPX_CAS_ACK;
431 rspPkt.rtntypU = U_CPX_CAS_ACK;
432 }
433
434 PCX_STR_LD: {
435 rspPkt.rtntyp = CPX_STR_LD; // code is done
436 rspPkt.rtntypU = U_CPX_STR_LD;
437 }
438
439 PCX_STR_ST: {
440 rspPkt.rtntyp = CPX_STR_ST; // code is done
441 rspPkt.rtntypU = U_CPX_STR_ST;
442 }
443
444 PCX_SWAP: {
445 rspPkt.rtntyp = CPX_SWAP_RTN; // will do ack as well.
446 rspPkt.rtntypU = U_CPX_SWAP_RTN; // will do U_CPX_SWAP_ACK as well.
447 }
448
449 PCX_MMU_LD: {
450 rspPkt.rtntyp = CPX_MMU_RTN; // code is done
451 rspPkt.rtntypU = U_CPX_MMU_RTN;
452 }
453
454 PCX_IFILL: {
455 if (reqPkt.inv == 0) {
456 if (myPort !== DEV_NCU) {
457 rspPkt.rtntyp = CPX_IFILL; // code is done
458 rspPkt.rtntypU = U_CPX_IFILL;
459 } else {
460 rspPkt.rtntyp = CPX_NCU_IFILL; // code is done
461 rspPkt.rtntypU = U_CPX_NCU_IFILL;
462 }
463 } else {
464 rspPkt.rtntyp = CPX_I_INVAL;
465 rspPkt.rtntypU = U_CPX_I_INVAL;
466 invField = I_INVAL;
467 }
468 }
469
470 default : {
471 reqPkt.print(myPort);
472 PR_ERROR (CLASSNAMEQ, MON_ERR,
473 psprintf ("T%d Port=%0d request type [128:124]=%b. ERROR FAIL: Unsupported rqtyp",thread,myPort,reqPkt.rqtyp));
474 reqPkt = null; rspPkt2 = null;
475 }
476 } // case
477
478
479 // finalize random values for response times
480 if (myPort == DEV_NCU)
481 void = rspPkt.randomize() with {hit == 1;};
482 else
483 void = rspPkt.randomize();
484
485
486 // do the response
487 case (rspPkt.rtntypU) {
488
489 U_CPX_LD, U_CPX_DIAG_LD,
490 U_CPX_STR_LD, U_CPX_MMU_RTN, U_CPX_PREF,
491 U_CPX_PREF_ICE, U_CPX_NCU_LD: {
492
493 integer i;
494
495 repeat (ordering(rspPkt, "LD RTN")) @(posedge portVar.$clk);
496 // get semaphore for this clock
497 semaphore_get(WAIT, ldstSyncLock, 1);
498
499 if (reqPkt.addr[39] && myPort == DEV_NCU) {
500
501 // is it a special address for us?
502// if (reqPkt.addr[IO_ASI_ADDR_NCU] == IO_ASI_CPU ||
503// reqPkt.addr[IO_ASI_ADDR_NCU] == IO_ASI_NCU) {
504 rspPkt.err[1] = ! gUtil.ioSpaceAccess(reqPkt.addr,
505 tmpData, *,
506 reqPkt.size,
507 thread, myPort);
508
509 if (reqPkt.size == 4)
510 PR_ERROR(CLASSNAMEQ, MON_ERROR, psprintf("TID %0d is doing a 16 byte load to I/O addr %0h!",reqPkt.tid,reqPkt.addr));
511
512 rspPkt.data = gUtil.copyDataByte(tmpData,reqPkt.size,reqPkt.addr[3:0]);
513// }
514//
515// } else if (reqPkt.addr[39] && myPort !== DEV_NCU &&
516// (reqPkt.addr[IO_ASI_ADDR_NCU] < 8'hA0 ||
517// reqPkt.addr[IO_ASI_ADDR_NCU] > 8'hBF) ) {
518// // I/O but not L2 CSRs
519// error("I/O LD to L2, but is not L2 CSRs");
520 } else { // LD from non-NCU space or L2 CSRs
521
522 // Address in req is quad word aligned.
523 // Access memory at double word boundaries.
524 tmpAddr = {reqPkt.addr[39:4],4'b0000};
525 rspPkt.data = gMem.read128(tmpAddr,myPort,1);
526 if (gParam.mcuMemPrint[READ]) {
527 printf("\n%7d00: dumpMem: dumping memory related to this request pkt:",get_cycle());
528 reqPkt.print(myPort);
529 gMem.dumpMem(reqPkt.addr[39:0] & 40'hFFFFFFFFC0, 8);
530 }
531
532 if (rspPkt.rtntypU == U_CPX_MMU_RTN)
533 rspPkt.wayMMUid = reqPkt.l1wayMMUid;
534
535 if (rspPkt.rtntypU == U_CPX_PREF) {
536 rspPkt.nc = 1;
537 rspPkt.pf = 1;
538 // prefetch data is irrelevant since data does not allocate in L1
539 rspPkt.data = {urandom(),urandom(),urandom(),urandom()};
540
541 // does this imply the the L1 does not have this line?
542
543 //invVector = getInvalVector(rspPkt.rtntypU, reqPkt, reqPkt.cpuId);
544 }
545
546 // evict line from L1 & L2.
547 // send invalidates to other cores for this address.
548 // do not send response to initiating core!!!
549 // Used by SW to flush lines in L2 based on an index and a
550 // way specified as part of the Physical Address in the instruction
551 // itself. Bits [39:37] of the PA has to be driven as 3'b011 by SW and
552 // the way,index,bank information would be on PA[21:18], PA[17:9] and
553 // PA[8:6] respectively.
554 if (rspPkt.rtntypU == U_CPX_PREF_ICE) {
555
556 // the BFM is not going to support this because the "address"
557 // only makes sense to L2 RTL. Can't properly handle this.
558 printf("\n\n%7d: WARNING, L2 BFM does not support prefetchICE, ignoring!\n\n\n");
559 return;
560
561 // create a single EVICTION packet and send it to every core needing it
562 rspPkt.targetPorts[8:0] = gParam.coreEnable;
563 rspPkt.rtntypU = U_CPX_EVICT;
564 rspPkt.rtntyp = CPX_EVICT;
565 rspPkt.l2miss = 0;
566 rspPkt.err = 0;
567 rspPkt.nc = 0;
568 rspPkt.pf = 0;
569
570 tmpPa = reqPkt.addr[39:0];
571
572 // gets evict vector and invals dup tags.
573 rspPkt.data = gUtil.evictVector(gParam.coreEnable,
574 tmpPa,
575 reqPkt.cpuId,
576 targetCores); // return val for target cores
577
578 rspPkt.targetPorts = targetCores;
579
580
581 // inval line from L1 & L2.
582 // send invalidates to other cores for this address.
583 // do not send response to initiating core!!!
584 if (rspPkt.data) {
585 // notify LDST sync just once when doing U_CPX_PREF_ICE
586 // no matter what targets get invalidated.
587 ldstSync(reqPkt.cpuId,rspPkt);
588 rspPkt.send(1);
589 }
590
591 @(posedge portVar.$clk);
592 semaphore_put(ldstSyncLock, 1 );
593
594 return; // due to U_CPX_PREF_ICE
595
596 } // U_CPX_PREF_ICE
597
598 } // l2 ld
599
600
601 // Plusargs to dump LD/ST to logfile
602 if (gParam.show_load) {
603 if (rspPkt.rtntypU == U_CPX_STR_LD)
604 PR_NORMAL(CLASSNAMEQ, MON_NORMAL, psprintf("Tx LOAD PA = %h DATA = %h TYPE = %0d",reqPkt.addr,rspPkt.data,rspPkt.rtntypU));
605 else
606 PR_NORMAL(CLASSNAMEQ, MON_NORMAL, psprintf("T%d LOAD PA = %h DATA = %h TYPE = %0d",reqPkt.tid,reqPkt.addr,rspPkt.data,rspPkt.rtntypU));
607 }
608
609 // notify LDST sync
610 ldstSync(reqPkt.cpuId,rspPkt);
611
612 // Update D$ tag table
613 if (reqPkt.nc == 0 && rspPkt.rtntypU !== U_CPX_PREF_ICE)
614 updateDtag(reqPkt, rspPkt, reqPkt.cpuId, TAG_VAL);
615
616#ifdef CCXDEVMEMBFM_DEBUG
617 // state of tag for line at this time
618 rspPkt.lineWay = lineState(reqPkt, *, 1);
619#endif
620
621 // queue packet for delivery, in this case, this BFM will drive it.
622 rspPkt.send(1);
623
624 @(posedge portVar.$clk);
625 semaphore_put(ldstSyncLock, 1 );
626
627
628 } // LD
629
630
631 U_CPX_ST, U_CPX_DIAG_ST,
632 U_CPX_STR_ST, U_CPX_BIS, U_CPX_BLK_ST: {
633
634
635 repeat (ordering(rspPkt, "ST RTN")) @(posedge portVar.$clk);
636 // get semaphore for this clock
637 semaphore_get(WAIT, ldstSyncLock, 1);
638
639 if (reqPkt.addr[39] && myPort == DEV_NCU) { // I/O ?
640
641 // is it a special address for us?
642// if (reqPkt.addr[IO_ASI_ADDR_NCU] == IO_ASI_CPU ||
643// reqPkt.addr[IO_ASI_ADDR_NCU] == IO_ASI_NCU) {
644 if (reqPkt.addr[IO_ASI_ADDR_REG] == ASI_SWVR_UDB_INTR_W) {
645 // Send Store Ack but don't store to anything
646 // Send INTERRUPT packet behind it
647 rspPkt2 = new(reqPkt);
648 rspPkt2 = rspPkt.object_copy();
649
650 // second packets must not have this set because it will
651 // cause outstandingRequests to decrement twice.
652 rspPkt2.ccxSourced = 0;
653 rspPkt2.sendPorts = 1 << myPort;
654 rspPkt2.createIntr(reqPkt.data[13:8],reqPkt.data[15:14],reqPkt.data[5:0]);
655 } else {
656 tmpData[63:0] = reqPkt.data;
657 void = gUtil.ioSpaceAccess(reqPkt.addr, tmpData, 0,
658 reqPkt.size, thread, myPort);
659// }
660 }
661// } else if (reqPkt.addr[39] && myPort !== DEV_NCU &&
662// (reqPkt.addr[39:32] < 8'hA0 || reqPkt.addr[39:32] > 8'hBF) ) {
663// // I/O but not L2 CSRs
664// error("I/O ST to L2, but it is not a L2 CSR!");
665 } else { // not NCU space, L2 or L2 CSR
666 // this only gets done on hit. nas never does this so we wont either.
667 // if (rspPkt.rtntypU == U_CPX_BIS)
668 // gMem.write512({reqPkt.addr[39:6],6'b000000}, 0, myPort);
669
670 // do not write if inv is set! BIS does not init w/ zeros.
671 if (reqPkt.inv == 0) {
672 gMem.writeBM({reqPkt.addr[39:3],3'b000}, reqPkt.data, reqPkt.size, myPort);
673 if (gParam.mcuMemPrint[WRITE]) {
674 printf("\n%7d00: dumpMem: dumping memory related to this request pkt:",get_cycle());
675 reqPkt.print(myPort);
676 gMem.dumpMem(reqPkt.addr & 40'hFFFFFFFFC0, 8);
677 }
678 }
679
680 }
681
682 // Plusargs to dump LD/ST to logfile
683 if (gParam.show_store) {
684 if (rspPkt.rtntypU == U_CPX_STR_ST)
685 PR_NORMAL(CLASSNAMEQ, MON_NORMAL,
686 psprintf("Tx STORE PA = %h DATA = %h BYTE_MASK = %b TYPE = %0d",
687 reqPkt.addr,reqPkt.data,reqPkt.size,rspPkt.rtntypU));
688 else
689 PR_NORMAL(CLASSNAMEQ, MON_NORMAL,
690 psprintf("T%d STORE PA = %h DATA = %h BYTE_MASK = %b TYPE = %0d",
691 reqPkt.tid,reqPkt.addr,reqPkt.data,reqPkt.size,rspPkt.rtntypU));
692 }
693
694 // L1 cache tags, get inv vec and invalidate all our dupe tags as needed. ST
695 invVector = 0;
696 targetCores = 0;
697 // always target the requester
698 targetCores[reqPkt.cpuId] = 1;
699
700 for (i=0;i<=gParam.coreMax;i++) {
701 tmpInvVect = getInvalVector(rspPkt.rtntypU, reqPkt, i);
702 if (tmpInvVect) targetCores[i] = 1;
703 invVector = invVector | tmpInvVect;
704 }
705
706 invField = 0;
707 rspPkt.data = {2'b0, reqPkt.l1wayBis,
708 invField, reqPkt.addr[5:4], reqPkt.cpuId[2:0],
709 reqPkt.addr[11:6],7'b0, reqPkt.addr[3],
710 reqPkt.size[7:0],invVector, reqPkt.data[63:0]};
711
712 if (rspPkt.rtntypU == U_CPX_STR_ST)
713 rspPkt.l2miss = 0;
714
715#ifdef CCXDEVMEMBFM_DEBUG
716 // state of tag for line at this time
717 rspPkt.lineWay = lineState(reqPkt, *, 1);
718#endif
719
720 // queue packet(s) for delivery, in this case, this BFM will drive it.
721 if ((reqPkt.addr[IO_ASI_ADDR_NCU] == IO_ASI_CPU ||
722 reqPkt.addr[IO_ASI_ADDR_NCU] == IO_ASI_NCU) &&
723 reqPkt.addr[IO_ASI_ADDR_REG] == ASI_SWVR_UDB_INTR_W) {
724 rspPkt.send(1);
725 repeat (rspPkt.pkt2Delay) @(posedge portVar.$clk);
726 // special interrupt "reflection"
727 rspPkt2.l2miss = 0;
728 rspPkt2.send(1);
729 } else {
730 // need to invalidate other cores on store/blkSt/BIS!
731 rspPkt.targetPorts = targetCores;
732 rspPkt.send(1);
733
734 }
735
736 // notify LDST sync
737 ldstSync(reqPkt.cpuId,rspPkt);
738
739 @(posedge portVar.$clk);
740 semaphore_put(ldstSyncLock, 1 );
741
742 } // U_CPX_ST, U_CPX_DIAG_ST, U_CPX_STR_ST, U_CPX_BIS
743
744
745 U_CPX_D_INVAL, U_CPX_I_INVAL: {
746
747 integer i;
748
749 repeat (ordering(rspPkt, "INVAL")) @(posedge portVar.$clk);
750 // get semaphore for this clock
751 semaphore_get(WAIT, ldstSyncLock, 1);
752
753 // Core wants to invalidate all entries in the cache line
754 if (invField == D_INVAL) {
755 for (i=0; i<=3; i=i+1) {
756 dtag[reqPkt.cpuId].write_tag(i,reqPkt.addr[10:4],29'b0,TAG_INVAL);
757 }
758 } else {
759 for (i=0; i<=7; i=i+1) {
760 itag[reqPkt.cpuId].write_tag(i,{1'b0,reqPkt.addr[10:5]},29'b0,TAG_INVAL);
761 }
762 }
763
764 invVector = 0;
765 rspPkt.data = {2'b0,reqPkt.l1wayBis,invField,reqPkt.addr[5:4],reqPkt.cpuId,
766 reqPkt.addr[11:6],7'b0,reqPkt.addr[3],reqPkt.size,invVector,reqPkt.data[63:0]};
767
768
769#ifdef CCXDEVMEMBFM_DEBUG
770 // state of tag for line at this time
771 rspPkt.lineWay = lineState(reqPkt, *, 1);
772#endif
773
774 // queue packet(s) for delivery, in this case, this BFM will drive it.
775 rspPkt.send(1);
776
777 // notify LDST sync
778 ldstSync(reqPkt.cpuId,rspPkt);
779
780 @(posedge portVar.$clk);
781 semaphore_put(ldstSyncLock, 1 );
782
783
784 } // U_CPX_D_INVAL, U_CPX_I_INVAL
785
786
787
788 U_CPX_CAS_RTN:
789 {
790
791 if (myPort == DEV_NCU) error("CAS not allowed at NCU"); // I/O
792
793 repeat (ordering(rspPkt, "CAS RTN")) @(posedge portVar.$clk);
794 // get semaphore for this clock
795 semaphore_get(WAIT, ldstSyncLock, 1);
796
797 // save away cas1Data, cas1Addr.
798 // hold until next packet (cas2)
799 cas1Addr[thread] = reqPkt.addr;
800 cas1Data[thread] = reqPkt.data;
801 tmpAddr = reqPkt.addr[39:0];
802 tmpData = gMem.read_mem(tmpAddr,myPort);
803
804 // remember to swap on following CAS2 pkt.
805 cas_swap[thread] = data_equal(cas1Data[thread],tmpData,reqPkt.size);
806 // for ldst sync
807 rspPkt.CASstore = cas_swap[thread];
808
809 // always return the LOAD data at cas1Addr in first response pkt.
810 rspPkt.data = gMem.read128(tmpAddr,myPort,1);
811 if (gParam.mcuMemPrint[READ]) {
812 printf("\n%7d00: dumpMem: dumping memory related to this request pkt:",get_cycle());
813 reqPkt.print(myPort);
814 gMem.dumpMem(tmpAddr & 40'hFFFFFFFFC0, 8);
815 }
816
817 // rspPkt.recvPort = reqPkt.cpuId;
818 // rspPkt.recvPorts = 1 << reqPkt.cpuId;
819 rspPkt.nc = 1;
820 rspPkt.tid = reqPkt.tid;
821 rspPkt.atmIf2 = 1;
822 rspPkt.wv = 0;
823
824 if (gParam.show_load) {
825 if (rspPkt.CASstore)
826 PR_NORMAL(CLASSNAMEQ, MON_NORMAL,
827 psprintf("T%d LOAD PA = %h DATA = %h TYPE = CAS swap will be true", reqPkt.tid,reqPkt.addr,tmpData));
828 else
829 PR_NORMAL(CLASSNAMEQ, MON_NORMAL,
830 psprintf("T%d LOAD PA = %h DATA = %h TYPE = CAS swap will be false", reqPkt.tid,reqPkt.addr,tmpData));
831 }
832
833
834#ifdef CCXDEVMEMBFM_DEBUG
835 // state of tag for line at this time
836 rspPkt.lineWay = lineState(reqPkt, *, 1);
837#endif
838
839 rspPkt.send(1);
840
841 // notify LDST sync
842 ldstSync(reqPkt.cpuId,rspPkt);
843
844 @(posedge portVar.$clk);
845 semaphore_put(ldstSyncLock, 1 );
846
847 } // U_CPX_CAS_RTN
848
849
850 U_CPX_CAS_ACK: {
851
852 if (myPort == DEV_NCU) error("CAS not allowed at NCU"); // I/O
853
854 repeat (ordering(rspPkt, "CAS ACK")) @(posedge portVar.$clk);
855 // get semaphore for this clock
856 semaphore_get(WAIT, ldstSyncLock, 1);
857
858 // do the swap here on the second pkt.
859
860 // compare the data at cas1Addr to the data cas1Data.
861 // if ==, swap cas2 data with the data at cas1Addr.
862 // always return the data at cas1Addr in first response pkt.
863 //
864 // cas1Data has rs2 data.
865 // cas1Addr has rs1 addr.
866 //
867 // cas2 data has rd.
868
869 // if cas_swap true from previous packet, write the rd/cas2 data to mem.
870 if (cas_swap[thread]) {
871 tmpAddr = cas1Addr[thread];
872 gMem.writeBM(tmpAddr[39:0], reqPkt.data, reqPkt.size, myPort);
873 if (gParam.mcuMemPrint[WRITE]) {
874 printf("\n%7d00: dumpMem: dumping memory related to this request pkt:",get_cycle());
875 reqPkt.print(myPort);
876 gMem.dumpMem(reqPkt.addr & 40'hFFFFFFFFC0, 8);
877 }
878
879 // for ldst sync
880 rspPkt.CASstore = 1;
881
882 // Plusargs to dump LD/ST to logfile
883 if (gParam.show_store && cas_swap[thread])
884 PR_NORMAL(CLASSNAMEQ, MON_NORMAL,
885 psprintf("T%d STORE PA = %h DATA = %h BYTE_MASK = %b TYPE = CAS swap true",
886 reqPkt.tid,reqPkt.addr,reqPkt.data,reqPkt.size));
887 cas_swap[thread] = 0;
888 }
889
890 // ack pkt
891 rspPkt.nc = 1;
892 rspPkt.tid = reqPkt.tid;
893 rspPkt.atmIf2 = 1;
894 rspPkt.wv = 0;
895
896 // L1 cache tags, get vec and invalidate all duplicate tags as needed. CAS
897 invVector = 0;
898 targetCores = 0;
899 // always target the requester
900 targetCores[reqPkt.cpuId] = 1;
901
902 for (i=0;i<=gParam.coreMax;i++) {
903 tmpInvVect = getInvalVector(rspPkt.rtntypU, reqPkt, i);
904 if (tmpInvVect) targetCores[i] = 1;
905 invVector = invVector | tmpInvVect;
906 }
907
908 invField = 0;
909 rspPkt.data = {2'b0,reqPkt.l1wayBis,invField,reqPkt.addr[5:4],reqPkt.cpuId,
910 reqPkt.addr[11:6],7'b0,reqPkt.addr[3],reqPkt.size,invVector,reqPkt.data[63:0]};
911
912
913#ifdef CCXDEVMEMBFM_DEBUG
914 // state of tag for line at this time
915 rspPkt.lineWay = lineState(reqPkt, *, 1);
916#endif
917
918 // queue packet for delivery, in this case, this BFM will drive it.
919 rspPkt.targetPorts = targetCores;
920 rspPkt.send(1);
921
922 // notify LDST sync
923 ldstSync(reqPkt.cpuId,rspPkt);
924
925 @(posedge portVar.$clk);
926 semaphore_put(ldstSyncLock, 1 );
927
928 } // U_CPX_CAS_ACK
929
930
931 U_CPX_SWAP_RTN, U_CPX_SWAP_ACK:
932 // do the swap, the return pkt, and the ack pkt here.
933 // we get addr and 32 bit swap data. Use size mask.
934 {
935 if (myPort == DEV_NCU) error("SWAP not allowed at NCU"); // I/O
936
937 fork {
938
939 repeat (ordering(rspPkt, "SWAP RTN")) @(posedge portVar.$clk);
940 // get semaphore for this clock
941 semaphore_get(WAIT, ldstSyncLock, 1);
942
943 // load
944 tmpAddr = {reqPkt.addr[39:4],4'b0000};
945 rspPkt.data = gMem.read128(tmpAddr,myPort,1);
946 if (gParam.mcuMemPrint[READ]) {
947 printf("\n%7d00: dumpMem: dumping memory related to this request pkt:",get_cycle());
948 reqPkt.print(myPort);
949 gMem.dumpMem(tmpAddr & 40'hFFFFFFFFC0, 8);
950 }
951
952 // Plusargs to dump LD/ST to logfile
953 if (gParam.show_load)
954 PR_NORMAL(CLASSNAMEQ, MON_NORMAL, psprintf("T%d LOAD PA = %h DATA = %h TYPE = SWAP",
955 reqPkt.tid,reqPkt.addr,rspPkt.data));
956
957 // return pkt
958 //
959 rspPkt.nc = 1;
960 rspPkt.tid = reqPkt.tid;
961 rspPkt.atmIf2 = 1;
962 rspPkt.wv = 0;
963 // for ldst sync
964 rspPkt.CASstore = 1;
965
966 // used by fork 2 when it proceeds
967 rspPkt2 = new(reqPkt);
968 rspPkt2 = rspPkt.object_copy();
969
970#ifdef CCXDEVMEMBFM_DEBUG
971 // state of tag for line at this time
972 rspPkt.lineWay = lineState(reqPkt, *, 1);
973#endif
974
975 // send load data
976 rspPkt.send(1);
977
978 // notify LDST sync
979 ldstSync(reqPkt.cpuId,rspPkt);
980
981 @(posedge portVar.$clk);
982 semaphore_put(ldstSyncLock, 1 );
983
984 } // fork 1
985
986 /////////////////////////////////
987
988 { // fork 2
989
990 delay(1);
991
992 // wait
993 repeat (ordering(rspPkt, "SWAP ACK")) @(posedge portVar.$clk);
994 // get semaphore for this clock
995 semaphore_get(WAIT, ldstSyncLock, 1);
996
997 // ack pkt
998 //
999 gMem.writeBM({reqPkt.addr[39:3],3'b000}, reqPkt.data, reqPkt.size, myPort);
1000 if (gParam.mcuMemPrint[WRITE]) {
1001 printf("\n%7d00: dumpMem: dumping memory related to this request pkt:",get_cycle());
1002 reqPkt.print(myPort);
1003 gMem.dumpMem(reqPkt.addr & 40'hFFFFFFFFC0, 8);
1004 }
1005
1006 rspPkt2.ccxSourced2 = reqPkt.ccxSourced;
1007 // second packet must not have ccxSourced set because it will
1008 // cause outstandingRequests to decrement twice.
1009 rspPkt2.ccxSourced = 0;
1010 rspPkt2.rtntyp = CPX_SWAP_ACK;
1011 rspPkt2.rtntypU = U_CPX_SWAP_ACK;
1012
1013 // L1 cache tags, get vec and invalidate all duplicate tags as needed. SW
1014 invVector = 0;
1015 targetCores = 0;
1016 // always target the requester
1017 targetCores[reqPkt.cpuId] = 1;
1018
1019 for (i=0;i<=gParam.coreMax;i++) {
1020 tmpInvVect = getInvalVector(rspPkt2.rtntypU, reqPkt, i);
1021 if (tmpInvVect) targetCores[i] = 1;
1022 invVector = invVector | tmpInvVect;
1023 }
1024
1025 // Vack
1026 invField = 0;
1027 rspPkt2.data = {2'b0,reqPkt.l1wayBis,invField,reqPkt.addr[5:4],reqPkt.cpuId,
1028 reqPkt.addr[11:6],7'b0,reqPkt.addr[3],reqPkt.size,invVector,reqPkt.data[63:0]};
1029
1030
1031 // Plusargs to dump LD/ST to logfile
1032 if (gParam.show_store)
1033 PR_NORMAL(CLASSNAMEQ, MON_NORMAL, psprintf("T%d STORE PA = %h DATA = %h BYTE_MASK = %b TYPE = SWAP",reqPkt.tid,reqPkt.addr,reqPkt.data,reqPkt.size));
1034
1035#ifdef CCXDEVMEMBFM_DEBUG
1036 // state of tag for line at this time
1037 rspPkt2.lineWay = lineState(reqPkt, *, 1);
1038#endif
1039
1040 // queue packet for delivery, in this case, this BFM will drive it.
1041 rspPkt2.targetPorts = targetCores;
1042 rspPkt2.send(1);
1043
1044 // notify LDST sync
1045 ldstSync(reqPkt.cpuId,rspPkt2);
1046
1047 @(posedge portVar.$clk);
1048 semaphore_put(ldstSyncLock, 1 );
1049
1050 } join none // all
1051
1052 } // PCX_SWAP_RTN
1053
1054
1055 U_CPX_IFILL, U_CPX_NCU_IFILL: {
1056
1057 repeat (ordering(rspPkt, "IFILL")) @(posedge portVar.$clk);
1058 // get semaphore for this clock
1059 semaphore_get(WAIT, ldstSyncLock, 1);
1060
1061 tmpAddr = reqPkt.addr;
1062
1063 // are we NCU? return 1 packet, not 2
1064 if (myPort == DEV_NCU) {
1065 // Set error bit on fetch to non-boot I/O to match NCU behavior
1066 if (tmpAddr[39] == 1 && tmpAddr[39:32] != 8'hff)
1067 rspPkt.err = 2'b10; // uncorrectable error
1068 rspPkt.wayf4b = 1; // 4 byte fill
1069 tmpAddr = {reqPkt.addr[39:4],4'b0}; // 4 byte addressing!!!
1070 rspPkt.data = gMem.read128(tmpAddr,myPort,1);
1071 if (gParam.mcuMemPrint[READ]) {
1072 printf("\n%7d00: dumpMem: dumping memory related to this request pkt:",get_cycle());
1073 reqPkt.print(myPort);
1074 gMem.dumpMem(tmpAddr & 40'hFFFFFFFFC0, 8);
1075 }
1076
1077 //printf("%0d: CcxDevMemBFM[%2d]::respond: T%d read @ reqPkt/tmp %0h/%0h\n", get_time(LO),myPort,reqPkt.tid,reqPkt.addr,tmpAddr);
1078 //printf("%0d: CcxDevMemBFM[%2d]::respond: T%d read data %0h\n", get_time(LO),myPort,reqPkt.tid,rspPkt.data);
1079
1080 // queue packet for delivery, this BFM instance will end up driving it.
1081 rspPkt.send(1);
1082
1083 } else { // L2$
1084 rspPkt2 = new(reqPkt);
1085 rspPkt2 = rspPkt.object_copy();
1086
1087 tmpAddr = {reqPkt.addr[39:5],5'b0};
1088 rspPkt.data = gMem.read128(tmpAddr,myPort, 1);
1089 if (gParam.mcuMemPrint[READ]) {
1090 printf("\n%7d00: dumpMem: dumping memory related to this request pkt:",get_cycle());
1091 reqPkt.print(myPort);
1092 gMem.dumpMem(tmpAddr & 40'hFFFFFFFFC0, 8);
1093 }
1094
1095 // second packets must not have this set because it will
1096 // cause outstandingRequests to decrement twice.
1097 rspPkt2.ccxSourced = 0;
1098
1099 tmpAddr = tmpAddr + 16; //5'b10000;
1100 rspPkt2.atmIf2 = 1;
1101 rspPkt2.l2miss = 0;
1102 rspPkt2.data = gMem.read128(tmpAddr,myPort, 1);
1103
1104#ifdef CCXDEVMEMBFM_DEBUG
1105 // state of tag for line at this time
1106 rspPkt.lineWay = lineState(reqPkt, *, 1);
1107#endif
1108 // L1$ tag update.
1109 updateItag(reqPkt, rspPkt, rspPkt2, reqPkt.cpuId, TAG_VAL);
1110
1111
1112 // queue packets for delivery.
1113 //
1114 // Atomics must stay in order. The CPX rtl will hold the first
1115 // pkt until the second pkt arrives. They will arrive at the core
1116 // back to back. Putting time between pkt1 and pkt2 tests the CCX only,
1117 // the core never sees time between them. The 2 pkts MUST go into the
1118 // mailbox back to back to avoid another pkt from this port getting between
1119 // them.
1120 rspPkt.send(1);
1121 rspPkt2.send(1);
1122
1123 }
1124
1125 // notify LDST sync
1126 // ldstSync(reqPkt.cpuId,rspPkt);
1127
1128 @(posedge portVar.$clk);
1129 semaphore_put(ldstSyncLock, 1 );
1130
1131 }
1132
1133
1134 default : {
1135 rspPkt.print(myPort);
1136 PR_ERROR (CLASSNAMEQ, MON_ERR,
1137 psprintf ("T%d Port=%0d rtntyp=%b. Unsupported rtntyp for CCX MEM device BFM.",thread,myPort, rspPkt.rtntyp));
1138 }
1139 } // case
1140
1141}
1142
1143
1144task CLASSNAME::updateDtag(PcxPkt reqPkt, CpxPkt rspPkt, reg [2:0] cpuId, integer how = TAG_VAL)
1145{
1146 reg [3:0] match;
1147
1148 if (myPort == DEV_NCU || cacheOff || reqPkt.nc == 1) return;
1149
1150 // Update D$ tag table
1151 dtag[cpuId].write_tag (reqPkt.l1wayMMUid,
1152 reqPkt.addr[10:4],
1153 reqPkt.addr[39:11],how);
1154
1155 // Invalidate the other (I) tag table
1156 match = itag[cpuId].get_way ("D, chk 4 hit in I:",
1157 {1'b0,reqPkt.addr[10:5]},
1158 reqPkt.addr[39:11]);
1159 if (match != 4'b0) {
1160 itag[cpuId].write_tag(match[3:1],{1'b0,reqPkt.addr[10:5]},29'b0,TAG_INVAL);
1161 rspPkt.wv = 1'b1;
1162 rspPkt.wayMMUid = match[3:2];
1163 rspPkt.wayf4b = match[1];
1164 }
1165
1166}
1167
1168
1169
1170task CLASSNAME::updateItag(PcxPkt reqPkt, CpxPkt rspPkt,
1171 CpxPkt rspPkt2 = null, reg [2:0] cpuId, integer how = TAG_VAL)
1172{
1173 reg [3:0] match;
1174
1175 if (myPort == DEV_NCU || cacheOff) return;
1176
1177 if (!reqPkt.nc) {
1178
1179 if (match != 4'b0)
1180 PR_ERROR(CLASSNAMEQ, MON_ERR,
1181 psprintf ("ERROR itag: DUT request to L2$ 0x%0h should have hit in the L1$.\n\n",reqPkt.addr));
1182
1183 // Update I$ tag table
1184 itag[cpuId].write_tag ({reqPkt.l1wayBis,reqPkt.l1wayMMUid},
1185 {1'b0,reqPkt.addr[10:5]},
1186 reqPkt.addr[39:11],how,1);
1187 }
1188
1189 // Invalidate the other (D) tag table (whether nc=0|1)
1190 match = dtag[cpuId].get_way ("I, chk 4 hit in D:",
1191 reqPkt.addr[10:4],
1192 reqPkt.addr[39:11]);
1193 if (match != 4'b0) {
1194 dtag[cpuId].write_tag({1'b0,match[3:2]},reqPkt.addr[10:4],29'b0,TAG_INVAL);
1195 rspPkt.wv = 1'b1;
1196 rspPkt.wayMMUid = match[3:2];
1197 }
1198 // ifill covers 2 D$ lines
1199 if (rspPkt2 !== null) {
1200 match = dtag[cpuId].get_way ("I, chk 4 hit in D:",
1201 reqPkt.addr[10:4]+1,
1202 reqPkt.addr[39:11]);
1203 if (match != 4'b0) {
1204 dtag[cpuId].write_tag({1'b0,match[3:2]},reqPkt.addr[10:4]+1,29'b0,TAG_INVAL);
1205 rspPkt2.wv = 1'b1;
1206 rspPkt2.wayMMUid = match[3:2];
1207 }
1208 }
1209
1210}
1211
1212
1213
1214// use to receive an expected packet.
1215// mainly for CCX testing.
1216//
1217// user passes in a packet whos fields are set to match the
1218// packet that should show up at this port. When it does, the
1219// caller is notified (toggle a var in the passed in packet) and
1220// the passed in packet will be populated with what showed up at the
1221// destinatin port. Unexpected (not registered via a call to this task)
1222// packets will cause failure.
1223task CLASSNAME::recv(BasePkt pktHndl) {
1224
1225 // PcxPkt pcxPkt;
1226
1227 // assign/cast pktHndl to be of PcxPkt type rather than base
1228 //cast_assign(pcxPkt,pktHndl);
1229
1230 // load signature hash. key is signature and data is clk count at call time.
1231 // expectedSig[pcxPkt.getVector()] = pktHndl;
1232 expectedSig[pktHndl.getVector()] = pktHndl;
1233
1234}
1235
1236// Mainly for CCX testing. Call when a pkt should no longer arrive.
1237// For CCX, a pkt should never intentionally get dropped so this may not get used.
1238task CLASSNAME::cancelRecv(BasePkt pktHndl) {
1239
1240 // PcxPkt pcxPkt;
1241
1242 // assign/cast pktHndl to be of PcxPkt type rather than base
1243 //cast_assign(pcxPkt,pktHndl);
1244
1245 // clear signature hash.
1246 // void = assoc_index(DELETE,expectedSig,pcxPkt.getVector());
1247 void = assoc_index(DELETE,expectedSig,pktHndl.getVector());
1248
1249}
1250
1251
1252
1253//----------------------------------------------------------
1254// Compare 2 data vectors using size as a mask
1255function reg CLASSNAME::data_equal (reg [63:0] data1,
1256 reg [63:0] data2,
1257 reg[7:0] size) {
1258
1259 reg eq0,eq1,eq2,eq3,eq4,eq5,eq6,eq7;
1260
1261 eq7 = !size[7] | (data1[63:56]==data2[63:56]);
1262 eq6 = !size[6] | (data1[55:48]==data2[55:48]);
1263 eq5 = !size[5] | (data1[47:40]==data2[47:40]);
1264 eq4 = !size[4] | (data1[39:32]==data2[39:32]);
1265 eq3 = !size[3] | (data1[31:24]==data2[31:24]);
1266 eq2 = !size[2] | (data1[23:16]==data2[23:16]);
1267 eq1 = !size[1] | (data1[15: 8]==data2[15: 8]);
1268 eq0 = !size[0] | (data1[ 7: 0]==data2[ 7: 0]);
1269
1270 data_equal = eq7 & eq6 & eq5 & eq4 & eq3 & eq2 & eq1 & eq0;
1271
1272}
1273
1274
1275
1276// hit indication, what L2 thinks the core L1 has.
1277// returns invalidation vector for the indicated core.
1278// Does the invalidate of our duplicate tags.
1279function reg [31:0] CLASSNAME::getInvalVector(integer type,
1280 PcxPkt reqPkt,
1281 reg [2:0] cpuId)
1282{
1283
1284 reg [31:0] invVect_d, invVect_i;
1285 reg [3:0] dmatch, imatch;
1286
1287 if (myPort == DEV_NCU || cacheOff) {
1288 getInvalVector = 0;
1289 return;
1290 }
1291
1292#ifdef CCXDEVMEMBFM_DEBUG
1293 // state of tag for line at this time
1294 dtag[cpuId].dump_line("getInvalVector D1:",
1295 reqPkt.addr[10:4],
1296 MON_ALWAYS);
1297#endif
1298
1299 // Check if store hit the D$ of given cpuId
1300 dmatch = dtag[cpuId].get_way("getInvalVector:",
1301 reqPkt.addr[10:4],
1302 reqPkt.addr[39:11]);
1303
1304 //create_vector (INSTR_TAG,dmatch,invVect_d,cpuId);
1305 invVect_d = dmatch << (cpuId * 4);
1306
1307 // Invalidate entry in given cpuId (all cpu's) D$ if found...
1308 // Do this for Stream ST, Atomics (CAS/SWAP), Block *ST.
1309 if ((type == U_CPX_STR_ST ||
1310 type == U_CPX_BIS ||
1311 type == U_CPX_CAS_ACK ||
1312 type == U_CPX_CAS_RTN ||
1313 type == U_CPX_BLK_ST ||
1314 type == U_CPX_SWAP_RTN ||
1315 type == U_CPX_SWAP_ACK ||
1316 reqPkt.cpuId !== cpuId) && // hitting core is not requesting core
1317 dmatch)
1318 dtag[cpuId].write_tag({1'b0,dmatch[3:2]},
1319 reqPkt.addr[10:4],
1320 29'b0,TAG_INVAL);
1321
1322 // Check if store hit the I$
1323 imatch = itag[cpuId].get_way("getInvalVector:",
1324 {1'b0,reqPkt.addr[10:5]},
1325 reqPkt.addr[39:11]);
1326
1327 // Invalidate entry in I$ if found
1328 if (imatch) itag[cpuId].write_tag(imatch[3:1],
1329 {1'b0,reqPkt.addr[10:5]},
1330 29'b0,TAG_INVAL);
1331
1332 //create_vector (INSTR_TAG,imatch,invVect_i,cpuId);
1333 invVect_i = imatch << (cpuId * 4);
1334
1335 // Per spec, you cannot get match in both I$ & D$
1336 if ((imatch!=0)&(dmatch!=0)) {
1337 PR_ERROR(CLASSNAMEQ, MON_ERR,
1338 psprintf ("found match in both D$ and I$ for core %0d. D$=%b, I$=%b",cpuId,dmatch,imatch));
1339 }
1340
1341 getInvalVector = invVect_d | invVect_i;
1342
1343
1344#ifdef CCXDEVMEMBFM_DEBUG
1345 // state of tag for line at this time
1346 dtag[cpuId].dump_line("getInvalVector D2:",
1347 reqPkt.addr[10:4],
1348 MON_ALWAYS);
1349#endif
1350
1351}
1352
1353
1354task CLASSNAME::ldstSync(reg [2:0] cpuId, CpxPkt rspPkt) {
1355
1356 if (rspPkt.ccxSourced || rspPkt.ccxSourced2 || rspPkt.rtntyp == CPX_EVICT) {
1357 // notify nas LD/ST Sync for all but these types.
1358 // CAS that writes to L2 (CASstore), gntTarget, pa, pkt.
1359 if (myPort > 7 &&
1360 rspPkt.rtntypU !== U_CPX_STR_LD &&
1361 rspPkt.rtntypU !== U_CPX_MMU_RTN &&
1362 rspPkt.rtntypU !== U_CPX_PREF) {
1363 // these are NR0 interface types (return to zero)
1364 gLdStSyncPort[myPort].$cid <= cpuId;
1365 gLdStSyncPort[myPort].$ctrue <= rspPkt.CASstore;
1366 //gLdStSyncPort[myPort].$swap <= (rspPkt.rtntypU == U_CPX_SWAP_ACK || rspPkt.rtntypU == U_CPX_SWAP_RTN); // swap;
1367 gLdStSyncPort[myPort].$swap <= 0;
1368 gLdStSyncPort[myPort].$pa <= rspPkt.addr;
1369 gLdStSyncPort[myPort].$pkt <= rspPkt.getVector();
1370 }
1371 }
1372
1373}
1374
1375
1376// special task to potentially create an eviction packet to
1377// send to some cores. This task will make sure that LDST sync
1378// gets notified correctly. It also makes sure that
1379// duplicate tag updating is ordered and sane. This "psudo request"
1380// is ordered like any other.
1381//
1382// Caller can specify a target address to evict. Will do nothing if address
1383// is not cached. Otherwise, we find an address.
1384task CcxDevMemBFM::enqueueEvict(reg [7:0] coreEnable,
1385 reg [39:0] evictPA = 40'hffffffffff,
1386 reg [3:0] cid = 4'hf,
1387 reg all_cores = 0,
1388 integer dCacheWeight = 60) {
1389
1390 ccxPort portVar = gCpxPort[myPort];
1391 reg [7:0] targets;
1392 CpxPkt pkt;
1393 reg [127:0] vect;
1394
1395
1396 pkt = new();
1397 //pkt.randomize();
1398 //pkt.responseDelay = pkt.pkt2Delay;
1399 pkt.responseDelay = 2;
1400 pkt.tid = cid;
1401 pkt.sendPorts = 1 << myPort;
1402 pkt.rtntyp = CPX_EVICT;
1403 pkt.rtntypU = U_CPX_EVICT;
1404 pkt.addr = evictPA;
1405 pkt.l2miss = 0;
1406
1407 repeat (ordering(pkt, "XEVICT")) @(posedge portVar.$clk);
1408 // get semaphore for this clock
1409 semaphore_get(WAIT, ldstSyncLock, 1);
1410
1411 // get vector and update L1 dup tags
1412 vect = gUtil.evictVector (coreEnable,
1413 evictPA,
1414 cid,
1415 targets);
1416
1417// vect = gUtil.evictVinv(coreEnable,
1418// targets,
1419// evictPA,
1420// cid,
1421// all_cores,
1422// dCacheWeight);
1423
1424#ifdef CCXDEVMEMBFM_DEBUG
1425 if (! targets) printf("EVICTION gUtil.evictVector did not return any targets!!!\n");
1426 else printf("EVICTION gUtil.evictVector return targets = %b vec = %h\n", targets,vect);
1427#endif
1428
1429 if (vect && targets) {
1430 pkt.targetPorts = targets;
1431 pkt.addr = evictPA;
1432 pkt.tid = cid;
1433 pkt.data = vect;
1434 ldstSync(0,pkt); // notify
1435 pkt.send(1); // doit
1436
1437 PR_NORMAL(CLASSNAMEQ, MON_NORMAL,
1438 psprintf ("Sending EVICTION pkt to cores targets=0x%h, a=0x%h, vec=0x%h",
1439 pkt.targetPorts,pkt.addr,pkt.data));
1440 } else pkt = null;
1441
1442 @(posedge portVar.$clk);
1443 semaphore_put(ldstSyncLock, 1 );
1444}
1445
1446
1447// used for debug only
1448function reg [3:0] CLASSNAME::lineState(PcxPkt reqPkt,
1449 string why="debug lineState:",
1450 reg quiet=1)
1451{
1452
1453 if (reqPkt.rqtypU == U_PCX_IFILL || reqPkt.rqtyp == PCX_IFILL) {
1454 lineState = itag[reqPkt.cpuId].get_way(why,
1455 {1'b0,reqPkt.addr[10:5]},
1456 reqPkt.addr[39:11]);
1457 if (!quiet)
1458 itag[reqPkt.cpuId].dump_line(why, reqPkt.addr[10:4],MON_INFO);
1459 }
1460 else {
1461 lineState = dtag[reqPkt.cpuId].get_way(why,
1462 reqPkt.addr[10:4],
1463 reqPkt.addr[39:11]);
1464 if (!quiet)
1465 dtag[reqPkt.cpuId].dump_line(why, reqPkt.addr[10:4],MON_INFO);
1466 }
1467
1468
1469}
1470
1471
1472// hold off the responses until outstandingReqs reaches amount.
1473// this will clump responses into bursts periodically.
1474task CLASSNAME::burstResp(integer amount)
1475{
1476 reg [63:0] tmp;
1477 reg iSync = 0;
1478 integer wait, reason;
1479 ccxPort portVar = gCpxPort[myPort];
1480
1481 if (gParam.burstSync == myPort-8 || gParam.burstSync == myPort) iSync = 1;
1482 wait = gParam.burstHoldoff;
1483 repeat (10) @(negedge gPcxPort[myPort].$clk);
1484 tmp = gUtil.getThreadEnables();
1485 while (tmp !== gOutOfBoot) wait_var(gOutOfBoot); // all threads out of boot
1486
1487 // make stall agreeable so we do not stall cores requests when trying to
1488 // build up a burst
1489 stallStart = amount + 6;
1490 PR_ALWAYS(CLASSNAMEQ, MON_ALWAYS,
1491 psprintf("Port %2d, stallStart changed to %0d due to burst option.",myPort, stallStart));
1492 while (1) {
1493 if (outstandingReqs < amount) { // just drain naturally if too many in queue
1494
1495 @(posedge portVar.$clk);
1496 semaphore_get(WAIT, ldstSyncLock, 1); // stop responding
1497
1498 // start respoding after amount or burstSync or x clocks
1499 fork
1500 {
1501 while (outstandingReqs < amount) wait_var(outstandingReqs); // wait
1502 reason = 1;
1503 }
1504 {
1505 repeat (wait) @(posedge gPcxPort[myPort].$clk); // but not too long
1506 reason = 2;
1507 }
1508 {
1509 wait_var(burstSync); // burst on sync when in use
1510 reason = 3;
1511 }
1512 join any
1513 terminate; // kill remaining forks
1514
1515 if (iSync) burstSync = ~burstSync; // signal the other banks
1516
1517 if (outstandingReqs >= 2)
1518 PR_INFO(CLASSNAMEQ, MON_INFO,
1519 psprintf("Port %2d, Letting %0d packets burst through (reason=%0d)",myPort, outstandingReqs, reason));
1520
1521 @(posedge portVar.$clk);
1522 semaphore_put(ldstSyncLock, 1 ); // allow normal responses
1523 }
1524 repeat (5) @(posedge gPcxPort[myPort].$clk); // give a little break
1525 } // rinse and repeat
1526}