| 1 | // ========== Copyright Header Begin ========================================== |
| 2 | // |
| 3 | // OpenSPARC T2 Processor File: irritator.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 <std_display_defines.vri> |
| 37 | #include <ccxDevicesDefines.vri> |
| 38 | |
| 39 | #include <globals.vri> |
| 40 | |
| 41 | #include <baseParamsClass.vrh> |
| 42 | #include <sparcParams.vrh> |
| 43 | #include <baseUtilsClass.vrh> |
| 44 | #include <sparcBenchUtils.vrh> |
| 45 | #include <std_display_class.vrh> |
| 46 | #include <basePktClass.vrh> |
| 47 | #include <cpxPktClass.vrh> |
| 48 | #include <pcxPktClass.vrh> |
| 49 | #include <ccxDevBaseBFM.vrh> |
| 50 | #include <ccxDevMemBFM.vrh> |
| 51 | #include <ccxDevSpcBFM.vrh> |
| 52 | #include <memArray.vrh> |
| 53 | #include <ccx_tag_class.vrh> |
| 54 | #include <baseCCXtrans.vrh> |
| 55 | |
| 56 | #define CLASSNAME Irritator |
| 57 | #define CLASSNAMEQ "Irritator" |
| 58 | |
| 59 | |
| 60 | //gCcxDevice[] 0-16 !== null |
| 61 | |
| 62 | class CLASSNAME extends BaseCCXtrans { |
| 63 | |
| 64 | local string className = "Irritator"; |
| 65 | |
| 66 | // rands |
| 67 | |
| 68 | // end rands |
| 69 | |
| 70 | |
| 71 | task new(StandardDisplay dbgHndl, reg l2BFMs); |
| 72 | task decker(); |
| 73 | task evictFlood(); |
| 74 | task bufferFlood(); |
| 75 | task randStores(); |
| 76 | task randStLd(); |
| 77 | task randLoads(); |
| 78 | } |
| 79 | |
| 80 | |
| 81 | task CLASSNAME::new(StandardDisplay dbgHndl, reg l2BFMs) { |
| 82 | super.new(dbgHndl, l2BFMs); |
| 83 | srandom(gSeed,this); |
| 84 | |
| 85 | // void = randomize(); |
| 86 | |
| 87 | anyMemPort = gCpxPort[0]; |
| 88 | anySpcPort = gPcxPort[0]; |
| 89 | |
| 90 | fork { |
| 91 | evictFlood(); |
| 92 | bufferFlood(); |
| 93 | randStores(); |
| 94 | randStLd(); |
| 95 | randLoads(); |
| 96 | } join none |
| 97 | |
| 98 | } |
| 99 | |
| 100 | |
| 101 | |
| 102 | ////////////////////////////////////////////////////// |
| 103 | // higher level tasks |
| 104 | ////////////////////////////////////////////////////// |
| 105 | |
| 106 | // enqueue a bunch of noop evictions for directed coverage. |
| 107 | // every source sends to every FloodTarget. No checking. |
| 108 | // +evictFloodAmount, +evictFloodFreq, +evictFloodTargets |
| 109 | task CLASSNAME::evictFlood() |
| 110 | { |
| 111 | |
| 112 | integer amount; |
| 113 | |
| 114 | if (! gParam.evictFloodFreq || |
| 115 | ! gParam.evictFloodAmount || |
| 116 | ! gParam.evictFloodTargets) return; |
| 117 | |
| 118 | if (gCcxDevice[8] == null || gCcxDevice[16] == null) |
| 119 | PR_ERROR(CLASSNAMEQ, MON_ERROR, |
| 120 | psprintf ("evictFlood task needs L2 BFMs and NCU BFM!")); |
| 121 | |
| 122 | amount = gParam.evictFloodAmount; |
| 123 | repeat (500) @(posedge anyMemPort.$clk); |
| 124 | while (amount) { |
| 125 | repeat (gParam.evictFloodFreq) @(posedge anyMemPort.$clk); |
| 126 | repeat (2) bogusEvict(gParam.evictFloodTargets, 8'hff); |
| 127 | repeat (2) super.sendIntr(0, 3, 0); |
| 128 | amount--; |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | |
| 133 | // For CCX coverage activity. 2 ifill resp followed by 1 eviction. (ncu does 3 interrupts) |
| 134 | // Will enqueue a bunch of ifill responses and noop evictions for directed coverage. |
| 135 | // Every source sends to ONE FloodTarget, all at once. No checking. |
| 136 | // |
| 137 | // bufferFloodFreq = getParam(DEC, "bufferFloodFreq", 0, 100000, 0); |
| 138 | // bufferFloodAmount = getParam(DEC, "bufferFloodAmount", 1, 100, 10); |
| 139 | // bufferFloodTarget = getParam(HEX, "bufferFloodTarget", 1, 7, 7); |
| 140 | task CLASSNAME::bufferFlood() |
| 141 | { |
| 142 | |
| 143 | integer amount; |
| 144 | |
| 145 | if (! gParam.bufferFloodFreq || |
| 146 | ! gParam.bufferFloodAmount || |
| 147 | ! gParam.bufferFloodTarget) return; |
| 148 | |
| 149 | if (gCcxDevice[8] == null || gCcxDevice[16] == null) |
| 150 | PR_ERROR(CLASSNAMEQ, MON_ERROR, |
| 151 | psprintf ("bufferFlood task needs L2 BFMs and NCU BFM!")); |
| 152 | |
| 153 | amount = gParam.bufferFloodAmount; |
| 154 | repeat (500) @(posedge anyMemPort.$clk); |
| 155 | while (amount) { |
| 156 | repeat (gParam.bufferFloodFreq) @(posedge anyMemPort.$clk); |
| 157 | bogusEvict(1<<gParam.bufferFloodTarget, 8'h0C); |
| 158 | @(posedge anyMemPort.$clk); |
| 159 | bogusEvict(1<<gParam.bufferFloodTarget, 8'h30); |
| 160 | super.sendIntr(gParam.bufferFloodTarget<<3, 3, 0); |
| 161 | @(posedge anyMemPort.$clk); |
| 162 | super.sendIntr(gParam.bufferFloodTarget<<3, 3, 0); |
| 163 | super.sendIntr(gParam.bufferFloodTarget<<3, 3, 0); |
| 164 | // pre pkt |
| 165 | ifillPair(gParam.bufferFloodTarget, 8'hff, |
| 166 | {urandom(),urandom()},{urandom(),urandom()}); |
| 167 | bogusEvict(1<<gParam.bufferFloodTarget, 8'hff); |
| 168 | bogusEvict(1<<gParam.bufferFloodTarget, 8'hff); |
| 169 | amount--; |
| 170 | } |
| 171 | } |
| 172 | |
| 173 | |
| 174 | |
| 175 | |
| 176 | // From all L2 ports, broadcast 1 eviction packet (with unique signature |
| 177 | // for each source) to every core. All core targets should have the exact |
| 178 | // packet stream coming out at the exact same time. Each send packet will |
| 179 | // go to 8 cores, each core will receive 8 packets. Will be 64 destination |
| 180 | // packets from 8 source packets. |
| 181 | task CLASSNAME::decker() { |
| 182 | |
| 183 | CpxPkt sndPkt[8]; |
| 184 | CpxPkt recvPkt[8][8]; |
| 185 | CpxPkt finalOrder[8][8]; |
| 186 | integer startTime; |
| 187 | shadow integer sp,rp; |
| 188 | reg [127:0] rand128, tmp128; |
| 189 | |
| 190 | |
| 191 | // create array of 8 unique source packets |
| 192 | for (sp=0;sp<8;sp++) { |
| 193 | sndPkt[sp] = new(); |
| 194 | rand128 = {urandom(),urandom(),urandom(),urandom()}; |
| 195 | sndPkt[sp].tid = rand128[2:0]; |
| 196 | sndPkt[sp].sendPorts = 1 << 8+sp; |
| 197 | sndPkt[sp].rtntyp = CPX_EVICT; |
| 198 | sndPkt[sp].rtntypU = U_CPX_EVICT; |
| 199 | sndPkt[sp].addr = rand128[39:0]; |
| 200 | sndPkt[sp].targetPorts = 8'hff; |
| 201 | sndPkt[sp].data = rand128; |
| 202 | } |
| 203 | |
| 204 | // register the 8 unique source packets |
| 205 | // at each destination. 64 total. |
| 206 | for (sp=0;sp<8;sp++) { |
| 207 | for (rp=0;rp<8;rp++) { |
| 208 | recvPkt[sp][rp] = new(); |
| 209 | recvPkt[sp][rp].signature = sndPkt[sp].makeSignature(); |
| 210 | recvPkt[sp][rp].targetPorts = 1<<rp; |
| 211 | recvPkt[sp][rp].recv(); // register arrival w/ BFM |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | |
| 216 | // initiator, 8 unique packets |
| 217 | for (sp=0;sp<8;sp++) { |
| 218 | sndPkt[sp].send(1); // let fly |
| 219 | PR_NORMAL(CLASSNAMEQ, MON_NORMAL, |
| 220 | psprintf ("Sending random EVICTION pkt from 0b%b to 0b%b, vec=0x%h", |
| 221 | sndPkt[sp].sendPorts, sndPkt[sp].targetPorts, |
| 222 | sndPkt[sp].getVector())); |
| 223 | } |
| 224 | |
| 225 | // for checker. Collect packets at destination. |
| 226 | // for each send port, collect 8 destination pkts. |
| 227 | for (sp=0;sp<8;sp++) { // for each send port |
| 228 | for (rp=0;rp<8;rp++) { // wait on/collect 8 packets in a row |
| 229 | fork { |
| 230 | wait_var(recvPkt[sp][rp].pktArrived); // 64 of these |
| 231 | // compare sndPkt[sp] to recvPkt[sp][rp] |
| 232 | if (recvPkt[sp][rp].makeSignature() !== sndPkt[sp].makeSignature()) |
| 233 | PR_ERROR(CLASSNAMEQ, MON_ERROR, |
| 234 | psprintf ("mismatch error, pkt from port %0d, to port %0d", sp, rp)); |
| 235 | finalOrder[sp][rp] = recvPkt[sp][rp]; |
| 236 | } join none |
| 237 | } |
| 238 | } |
| 239 | wait_child(); // wait for 64 pkts to arrive |
| 240 | |
| 241 | |
| 242 | // now make sure that every recv port got the same packets in |
| 243 | // the same order at the same time. Order is implied in the finalOrder array. |
| 244 | // Time is stored in the recieved packets. Compare time along with order. |
| 245 | for (rp=0;rp<8;rp++) { // for each recv port |
| 246 | for (sp=0;sp<7;sp++) { // make sure all packest are same for that clock |
| 247 | |
| 248 | // arrivial times (as loaded into finalOrder array) must inc by one, |
| 249 | // or dec by one depending on arb direction. |
| 250 | if (sp == 0 && rp == 0) startTime = finalOrder[rp][sp].arrivalTime; |
| 251 | |
| 252 | if (finalOrder[rp][sp].getVector() !== finalOrder[rp][sp+1].getVector() || |
| 253 | finalOrder[rp][sp].arrivalTime !== finalOrder[rp][sp+1].arrivalTime || |
| 254 | (finalOrder[rp][sp].arrivalTime !== startTime+rp && finalOrder[rp][sp].arrivalTime !== startTime-rp)) |
| 255 | PR_ERROR(CLASSNAMEQ, MON_ERROR, |
| 256 | psprintf ("decker ORDER/TIME mismatch error, [%0d][%0d] not == to [%0d][%0d]", rp, sp, rp, sp+1)); |
| 257 | printf("pkt sp=%0d,rp=%0d: vec=%h, time=%0d\n", rp, sp, finalOrder[rp][sp].getVector(), finalOrder[rp][sp].arrivalTime); |
| 258 | } |
| 259 | printf("pkt sp=%0d,rp=%0d: vec=%h, time=%0d\n", rp, sp, finalOrder[rp][sp].getVector(), finalOrder[rp][sp].arrivalTime); |
| 260 | } |
| 261 | |
| 262 | } |
| 263 | |
| 264 | |
| 265 | // send a bunch of store packets |
| 266 | // irritStFreq |
| 267 | // irritStAdr1 |
| 268 | // irritStAdr2 |
| 269 | task CLASSNAME::randStores() { |
| 270 | |
| 271 | integer i; |
| 272 | |
| 273 | // if (! gParam.irritStFreq) return; |
| 274 | // spcCheck("randStores"); |
| 275 | |
| 276 | |
| 277 | } |
| 278 | |
| 279 | |
| 280 | // send a bunch of load packets. This will mess up a real |
| 281 | // L2/core if the packet core is incorrect (same as real core)! |
| 282 | // irritLdFreq |
| 283 | // irritLdAdr1 |
| 284 | // irritLdAdr2 |
| 285 | task CLASSNAME::randLoads() { |
| 286 | |
| 287 | integer i; |
| 288 | PcxPkt pkt; |
| 289 | reg [31:0] rnd; |
| 290 | |
| 291 | |
| 292 | // // if (! gParam.irritLdFreq) return; |
| 293 | // spcCheck("randLoads"); |
| 294 | // |
| 295 | // rnd = urandom(); |
| 296 | // |
| 297 | // // create load pkt |
| 298 | // pkt = new(); |
| 299 | // |
| 300 | // pickCore(pkt.cpuId, pkt.sendPorts); |
| 301 | // pkt.nc = 0; |
| 302 | // pkt.inv = 0; |
| 303 | // pkt.pf = 0; |
| 304 | // pkt.l1wayBis = rnd[2:0]; |
| 305 | // pkt.l1wayMMUid = rnd[5:3]; |
| 306 | // pkt.size = ; |
| 307 | // pkt.tid = random(); |
| 308 | // pkt.rqtyp = |
| 309 | // pkt.rqtypU = |
| 310 | // pkt.addr = |
| 311 | // pkt.targetPorts = |
| 312 | // |
| 313 | // // end to end checking |
| 314 | // // pktRecv.signature = pkt.makeSignature(); |
| 315 | // // pktRecv.targetPorts = |
| 316 | // // pktRecv.recv(); |
| 317 | // |
| 318 | // |
| 319 | // pkt.send(1); // doit |
| 320 | // |
| 321 | // PR_NORMAL(CLASSNAMEQ, MON_NORMAL, |
| 322 | // psprintf ("Sending bogus EVICTION pkt to targets=0b%b, a=0x%h, vec=0x%h", |
| 323 | // pkt.targetPorts,0,0)); |
| 324 | |
| 325 | } |
| 326 | |
| 327 | |
| 328 | // send a bunch of checked st -> ld packet pairs |
| 329 | // irritLdStFreq |
| 330 | // irritLdStAdr1 |
| 331 | // irritLdStAdr2 |
| 332 | task CLASSNAME::randStLd() { |
| 333 | |
| 334 | integer i; |
| 335 | |
| 336 | // if (! gParam.irritLdStFreq) return; |
| 337 | // spcCheck("randStLd"); |
| 338 | |
| 339 | |
| 340 | } |