Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / env / common / vera / classes / sparcBenchUtils.vr
CommitLineData
86530b38
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: sparcBenchUtils.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 <std_display_class.vrh>
38#include <plusArgMacros.vri>
39#include <defines.vri>
40
41#include <cmp.vri>
42#include <globals.vri>
43
44#ifndef FC_BENCH
45#ifndef FC_SCAN_BENCH
46#include <verilog_tasks_ncu.vri>
47#endif
48#endif
49
50// mem slam, reg slam
51#include <verilog_tasks_misc.vri>
52
53#include <std_display_class.vrh>
54#include <baseParamsClass.vrh>
55#include <sparcParams.vrh>
56#include <baseUtilsClass.vrh>
57#include <memArray.vrh>
58
59#ifndef CCM_BENCH
60#ifndef FC_BENCH
61#ifndef FC_SCAN_BENCH
62#include <ccx_tag_class.vrh>
63#endif
64#endif
65#endif
66
67#include <sparcBenchUtils_if.vrh>
68
69#define CLASSNAME SparcBenchUtils
70#define CLASSNAMEQ "SparcBenchUtils"
71
72class CLASSNAME extends BaseUtils {
73
74 local string className = "SparcBenchUtils";
75 local StandardDisplay dbg;
76 local reg noNCUcheck = 0;
77 local reg failNCUcheck = 0;
78
79 // rands
80 local randc reg [5:0] startThread;
81 local randc reg [2:0] randCID;
82 local rand integer parkWait;
83 // end rands
84
85 // constraints
86 constraint parkWait_c {
87 parkWait <= gParam.por_delay_max;
88 parkWait >= gParam.por_delay_min;
89 }
90 // end constraints
91
92
93 task new(StandardDisplay dbgHndl, integer clockPeriod = 100);
94
95 task resetDut();
96
97 function reg ioSpaceAccess(reg [63:0] addr, // full addr of request
98 var reg [127:0] data, // r/w data
99 reg read = 1, // request is read, else write
100 reg [7:0] size = 8'hff, // write byte mask
101 integer thread = 99, // please provide
102 integer myPort = 99); // optional for messaging
103
104 function reg [127:0] copyDataByte (reg [127:0] data,
105 reg [7:0] size,
106 reg [3:0] offset);
107
108 function reg [63:0] evictAddr (reg [7:0] core_enable,
109 var reg [2:0] cidUsed,
110 reg [3:0] cid = 4'hf,
111 integer dCacheWeight = 60);
112
113 function reg [127:0] evictVector (reg [7:0] core_enable,
114 reg [63:0] evict_pa,
115 reg [2:0] cpuId,
116 var reg [7:0] targets);
117
118 function reg [63:0] getThreadEnables();
119 function reg [63:0] getRunStatus();
120 function reg [2:0] whichBank(reg [63:0] addr);
121}
122
123
124//----------------------------------------------------------
125// Do not call randomize() in this classes new() task.
126// The final class extention of this class must (does) do that in its new()!
127// Go ahead an assume that the first set of random numbers are available.
128task CLASSNAME::new(StandardDisplay dbgHndl, integer clockPeriod = 100) {
129 super.new(dbgHndl, clockPeriod);
130 this.dbg = dbgHndl;
131 if (mChkPlusarg(noNCUcheck)) noNCUcheck = 1;
132 if (mChkPlusarg(failNCUcheck)) failNCUcheck = 1;
133}
134
135
136// call AFTER time zero
137function reg [63:0] CLASSNAME::getThreadEnables() {
138 //getThreadEnables = sparcBenchUtils_if.th_check_enable; // -vcs_run_args=+thread=1
139 getThreadEnables = gParam.finishMask; // this is better
140}
141
142// call AFTER time zero. gets core_running_status.
143function reg [63:0] CLASSNAME::getRunStatus() {
144 getRunStatus = sparcBenchUtils_if.core_running_status;
145}
146
147
148// return which bank this address goes to.
149// for partial bank mode
150function reg [2:0] CLASSNAME::whichBank(reg [63:0] addr) {
151
152 case (gParam.bank_set_mask) {
153 1: whichBank = addr[6];
154 2: whichBank = {2'b01,addr[6]};
155 3: whichBank = {1'b0,addr[7:6]};
156 4: whichBank = {2'b10,addr[6]};
157 5: whichBank = {addr[7],1'b0,addr[6]};
158 6: whichBank = {addr[7],~addr[7],addr[6]};
159 8: whichBank = {2'b11,addr[6]};
160 9: whichBank = {addr[7],addr[7],addr[6]};
161 10: whichBank = {addr[7],1'b1,addr[6]};
162 12: whichBank = {1'b1,addr[7],addr[6]};
163 15: whichBank = {addr[8],addr[7],addr[6]};
164 default: error("bank_set_mask is illegal\n");
165 }
166
167}
168
169
170
171//----------------------------------------------------------
172// start threads
173//
174// rules:
175// 1 - always start with the lowest core, after that randomize core selection.
176// 2 - in a core, always start the lowest thread first.
177// 3 - after each core has had its lowest thread started, randomize the
178// rest of the threads.
179//
180
181task CLASSNAME::resetDut () {
182
183
184 //reg [31:0] resetThis;
185 reg [63:0] threadEnables;
186 integer core, tid, tmp;
187
188 integer lowCore; // lowest core from threadEnables
189 integer lowThread [8]; // lowest thread in each core
190 reg [63:0] doneThreads; // have been started already
191 reg [7:0] doneCores; // have been started already
192
193
194#ifndef FC_BENCH
195#ifndef FC_SCAN_BENCH
196
197 for (tid=0; tid<8; tid++) lowThread[tid] = 32'hx;
198
199 void = this.rand_mode(OFF, "startThread");
200
201 // do not unpark too early.
202 if (sparcBenchUtils_if.core_cycle_cnt < 12)
203 repeat (12 - sparcBenchUtils_if.core_cycle_cnt)
204 @(negedge sparcBenchUtils_if.clk);
205
206 // range is 28-48 (38 ideal) cycles from time zero if +forcePORstate
207 if (gParam.forcePORstate) {
208 if (sparcBenchUtils_if.core_cycle_cnt < 38)
209 repeat (38 - sparcBenchUtils_if.core_cycle_cnt)
210 @(negedge sparcBenchUtils_if.clk);
211 }
212
213 threadEnables = sparcBenchUtils_if.th_check_enable; // -vcs_run_args=+thread=1
214 if (! threadEnables) {
215 PR_ALWAYS(className, MON_ALWAYS,
216 psprintf("Unparking threads: th_check_enable = 0, Will not unpark ANY threads!!!"));
217 return;
218 }
219 PR_ALWAYS(className, MON_ALWAYS,
220 psprintf("Unparking threads: th_check_enable = %h",threadEnables));
221
222 // find lowest core
223 for (core=0; core<8; core++) {
224 if (|threadEnables[7+(core*8):core*8]) {
225 lowCore = core;
226 break;
227 } else doneCores[core] = 1;
228 }
229
230 // find lowest thread in each core
231 for (core=lowCore; core<8; core++) {
232 for (tid=0; tid<8; tid++) {
233 if (threadEnables[tid+(8*core)] == 1) {
234 lowThread[core] = tid;
235 break;
236 }
237 }
238 }
239
240 doneThreads = ~threadEnables; // call unused tids done for starters
241
242 PR_ALWAYS(className, MON_ALWAYS,
243 psprintf("Unparking: low core = %0d, low threads (0-07): %1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d",lowCore,lowThread[7],lowThread[6],lowThread[5],lowThread[4],lowThread[3],lowThread[2],lowThread[1],lowThread[0]));
244 PR_ALWAYS(className, MON_ALWAYS,
245 psprintf("Unparking: low core = %0d, low threads (0-63): %2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d",lowCore,lowThread[7]+56,lowThread[6]+48,lowThread[5]+40,lowThread[4]+32,lowThread[3]+24,lowThread[2]+16,lowThread[1]+8,lowThread[0]));
246
247 // POR threads in random orders after lowest core lowest tid
248 // but lowest first for each core.
249 // this is lowest first...
250 tmp = (lowCore*8)+lowThread[lowCore];
251 verilog_write_cmp_reg({ASI_CMP_CORE,ASI_CMP_CORE_RUNNING_W1S},
252 1 << tmp, tmp);
253
254 doneThreads[tmp] = 1; // mark it done
255 doneCores[lowCore] = &doneThreads[7+(lowCore*8):lowCore*8]; // core done?
256
257 PR_ALWAYS(className, MON_ALWAYS,
258 psprintf("T%0d unparked (lowest tid in lowest core)\n",tmp));
259
260 // quick check
261 if (doneThreads !== 64'hffffffffffffffff) {
262
263 // now the rest
264
265 // start the lowest thread on each core (except lowest core).
266 // they could be chosen at random or sequential.
267 repeat (8) {
268 core = randCID;
269 void = this.randomize();
270 if (core == lowCore || doneCores[core]) continue;
271 if (lowThread[core] !== 32'hx) {
272 tmp = (core*8)+lowThread[core];
273 // parkWait = urandom_range(gParam.por_delay_max,gParam.por_delay_min);
274 // PR_DEBUG (className, MON_DEBUG,
275 // psprintf("T%0d post unpark delay %d\n",get_cycle(),resetThis,del));
276 repeat (parkWait) @(posedge sparcBenchUtils_if.clk);
277 verilog_write_cmp_reg({ASI_CMP_CORE,ASI_CMP_CORE_RUNNING_W1S},
278 1 << tmp, tmp);
279 PR_ALWAYS(className, MON_ALWAYS,
280 psprintf("T%0d unparked (lowest tid in core)\n",tmp));
281 doneThreads[tmp] = 1; // mark it done
282 doneCores[core] = &doneThreads[7+(core*8):core*8]; // core done?
283 }
284 }
285
286 // start the remaining threads at random
287 repeat (64) {
288 if (doneThreads[startThread] == 0) {
289 void = this.randomize();
290 // parkWait = urandom_range(gParam.por_delay_max,gParam.por_delay_min);
291 // PR_DEBUG (className, MON_DEBUG,
292 // psprintf("T%0d post unpark delay %d\n",get_cycle(),resetThis,del));
293 repeat (parkWait) @(posedge sparcBenchUtils_if.clk);
294
295 verilog_write_cmp_reg({ASI_CMP_CORE,ASI_CMP_CORE_RUNNING_W1S},
296 1 << startThread,
297 startThread);
298 PR_ALWAYS(className, MON_ALWAYS,
299 psprintf("T%0d unparked (remaining non-lowest tids)\n",startThread));
300 doneThreads[startThread] = 1; // mark it done
301
302 }
303 void = this.rand_mode(ON, "startThread");
304 void = this.randomize();
305 void = this.rand_mode(OFF, "startThread");
306 }
307
308 }
309
310#endif
311#endif
312}
313
314/*
315task CLASSNAME::resetDut () {
316
317
318 reg [31:0] tid, resetThis;
319 reg [63:0] threadEnables;
320 integer lowThread, del;
321
322#ifndef FC_BENCH
323
324 void = this.rand_mode(OFF, "startThread");
325
326 repeat (5) @(negedge sparcBenchUtils_if.clk);
327
328 threadEnables = sparcBenchUtils_if.th_check_enable; // -vcs_run_args=+thread=1
329
330 PR_ALWAYS(className, MON_ALWAYS,
331 psprintf("Unparking threads: th_check_enable = %h",threadEnables));
332
333 // find lowest thread
334 for (tid=0; tid<=63; tid++) {
335 if (threadEnables[tid] == 1) {
336 lowThread = tid;
337 break;
338 }
339 }
340
341 //POR threads in random orders after lowest
342 verilog_write_cmp_reg({ASI_CMP_CORE,ASI_CMP_CORE_RUNNING_W1S},
343 1<<lowThread,
344 lowThread);
345 PR_ALWAYS(className, MON_ALWAYS,
346 psprintf("T%0d unparked (first)\n",lowThread));
347
348 repeat (64) {
349 if (threadEnables[startThread] == 1 && startThread !== lowThread) {
350 del = urandom_range(gParam.por_delay_max,gParam.por_delay_min);
351 // PR_DEBUG (className, MON_DEBUG,
352 // psprintf("T%0d post unpark delay %d\n",get_cycle(),resetThis,del));
353 repeat (del) @(posedge sparcBenchUtils_if.clk);
354
355 verilog_write_cmp_reg({ASI_CMP_CORE,ASI_CMP_CORE_RUNNING_W1S},
356 1<<startThread,
357 startThread);
358 PR_ALWAYS(className, MON_ALWAYS,
359 psprintf("T%0d unparked\n",startThread));
360
361 }
362 void = this.rand_mode(ON, "startThread");
363 void = this.randomize();
364 void = this.rand_mode(OFF, "startThread");
365 }
366
367#endif
368
369}
370*/
371
372
373
374
375
376//----------------------------------------------------------
377// Is address allowed at NCU for a read or write? Returns true if the
378// r/w was OK. If the return is false, the response packet MUST set the
379// error indication just as a real NCU would. The caller has to do
380// this!!! Also returns the data for the address to the caller. Zeros
381// will be returned for addresses that have never been written (except
382// 0x82 RNG).
383//
384// Certain ASI registers (CMP) may be implemented in verilog.
385// We will detect that here and do the right thing.
386//
387// Any write to any address that isn't explicitly defined will be
388// silently dropped. That includes reserved and not supported regions.
389// It also includes unimplemented addresses within a region. (For
390// example, the 0x90 region is for IO mapped ASI registers, but there
391// aren't very many. Any write to an address that isn't mapped to a
392// register will get dropped by NCU RTL, *BUT* this function allows the
393
394//
395// Real world store example:
396// * The LSU sends the NCU a store.
397// * The NCU acks the store - always.
398// * Since the store is ack'ed, software sees it as done.
399// * The NCU trys to figure out where the write should go.
400// If it can't figure it out, it drops it.
401// * The SOC units themselves could also drop it if the NCU
402// forwarded them a request that they don't support.
403//
404// This function will use the following table to define it's behavior.
405// Any range identified with ERROR *must* cause a load error response packet
406// to be returned to the core. THE USER/CALLER MUST DO THIS!!! This will
407// cause a trap to be taken by the core. In order for nas to take the
408// same trap, we need to add this case to the current interrupt sync
409// mechanism. Reads from 0x82 will return random data. Currently, only
410// 0xFF will be considered 100% read only.
411//
412// OLD Address [39:32] behavior
413// OLD --------------- --------
414// OLD 0x80 NCU R/W allowed
415// OLD 0x81 NIU R/W allowed
416// OLD * 0x82 RNG (Random Number Generator) IGNORE writes
417// OLD * 0x83 CCU R/W allowed
418// OLD 0x84 MCUs R/W allowed
419// OLD 0x85 TCU (JTAG/TAP. NCU/Core will not initiate) ERROR on read
420// OLD * 0x86 TAP to ASI (not supported) ERROR on read
421// OLD * 0x87 TAP to L2 CSR (not supported) ERROR on read
422// OLD 0x88 DMUCSR R/W allowed
423// OLD 0x89 RST R/W allowed
424// OLD 0x8A-0x8F Reserved ERROR on read
425// OLD 0x90 ASI CPU shared registers R/W allowed
426// OLD 0x91-0x9F Reserved ERROR on read
427// OLD 0xA0-0xBF L2 CSR (never comes to NCU) ERROR on read
428// OLD 0xC0-0xCF PCIE (64GB) / DMUPIO R/W allowed
429// OLD 0xD0-0xFE Reserved ERROR on read
430// OLD 0xFF SSI (boot ROM) IGNORE writes
431//
432// Address [39:32] behavior
433// --------------- --------
434// 0x80 NCU R/W allowed
435// 0x81 NIU R/W allowed
436// 0x82 Reserved ERROR on read
437// 0x83 CCU (+0x30 is Random Number Generator) R/W allowed
438// 0x84 MCUs R/W allowed
439// 0x85 TCU (JTAG/TAP) R/W allowed
440// 0x86 Debug R/W allowed
441// 0x87 Reserved ERROR on read
442// 0x88 DMU R/W allowed
443// 0x89 RST R/W allowed
444// 0x8A-0x8F Reserved ERROR on read
445// 0x90 ASI CPU shared registers R/W allowed
446// 0x91-0x9F Reserved ERROR on read
447// 0xA0-0xBF L2 CSR (never goes to NCU) ERROR on read
448// 0xC0-0xCF PCIE (64GB) / DMUPIO R/W allowed
449// 0xD0-0xFE Reserved ERROR on read
450// 0xFF SSI (boot ROM) IGNORE writes
451//
452// To disable the CPX pkt error response and allow full R/W of ALL
453// addresses by the NCU model (except writes to 0xFF) +noNCUcheck can be
454// used. Until Riesling/nas is updated with interrupt sync, and a
455// specific knowledge of the I/O map, +noNCUcheck could possibly be used.
456// The plus arg +noNCUcheck is normally not recommended because it
457// presents a behavior that IS NOT at all like a real N2 (so forget I
458// even mentioned it)!
459//
460// To always fail the simulation on error ("ERROR on read" space was
461// accessed or 0xFF was written), use +failNCUcheck. This would be a good
462// way to find "bad" diags.
463//
464//
465function reg CLASSNAME::ioSpaceAccess(reg [63:0] addr, // full addr of request
466 var reg [127:0] data, // r/w data
467 reg read = 1, // request is read, else write
468 reg [7:0] size = 8'hff, // write mask, read size
469 integer thread = 99,
470 integer myPort = 99) // optional for messaging
471{
472
473 reg [63:0] tmp64;
474
475#ifndef NCURTL
476#ifndef FC_BENCH
477#ifndef FC_SCAN_BENCH
478
479 PR_INFO ("ioaccess", MON_INFO,
480 psprintf("addr = %h data = %h R/W = %b size = %h thread = %0d myPort = %0d",
481 addr,data,read,size,thread,myPort));
482
483 ioSpaceAccess = 1; // no error
484 addr = addr & 64'hfffffffffffffff8;
485 if (read) data = 128'hdeaddeaddeaddeaddeaddeaddeaddead;
486
487 // detect special registers implemented in verilog.
488 if (
489 (addr[IO_ASI_ADDR_NCU] == 8'h90 &&
490 (addr[IO_ASI_ADDR_REG] == ASI_CMP_CORE ||
491 addr[IO_ASI_ADDR_ADR] == ASI_WMR_VEC_MASK_ADR ||
492 addr[IO_ASI_ADDR_ADR] == ASI_L2_IDX_HASH_EN_ADR ||
493 addr[IO_ASI_ADDR_ADR] == ASI_CMP_TICK_ENABLE_ADR)) ||
494 (addr == ASI_RESET_STAT)
495 ) {
496
497 if (thread == 99) thread = addr[IO_ASI_ADDR_CT];
498 if (read == 0)
499 verilog_write_cmp_reg(addr,data[63:0],thread);
500 else
501 {
502 verilog_read_cmp_reg(addr,tmp64,thread);
503 data = {tmp64,tmp64};
504 }
505
506 PR_INFO ("ioaccess", MON_INFO,
507 psprintf("err = %b Special IO Register Access (i.e. CMP reg, etc)",
508 ioSpaceAccess));
509 return;
510 }
511
512
513 case (addr[IO_ASI_ADDR_NCU]) {
514 8'h80, 8'h81, 8'h83, 8'h84, 8'h85, 8'h86, 8'h88, 8'h89: {
515 // 8'h83 +0x30 is Random Number Generator
516 if (addr[39:0] == 40'h83_0000_0030) {
517 if (read) {
518 data[63:0] = {urandom(),urandom()};
519 // review getting socket errors
520 #ifndef GATESIM
521 verilog_mem_slam(addr[39:0],
522 data[63:0],
523 8'hff,
524 "NCU BFM");
525 #endif
526 }
527 } else {
528 if (read) data = gMem.read128(addr,myPort, 1);
529 else gMem.writeBM(addr, data[63:0], size, myPort);
530 }
531 }
532 8'h82, 8'h87, 8'h8a, 8'h8b, 8'h8c, 8'h8d, 8'h8e, 8'h8f: { // reserved
533 ioSpaceAccess = 0;
534 }
535 } // case
536
537 case (addr[39:36]) {
538 4'h9: {// 0x90 ASI CPU shared registers
539 if (addr[IO_ASI_ADDR_NCU] == 8'h90) { // 0x90 ASI CPU shared registers
540 // Certain ASI registers (CMP) may be implemented in verilog.
541 // The code that calls this function MUST filter those out
542 // and do the right thing. We will not attempt that here!!!
543 if (read) data = gMem.read128(addr,myPort, 1);
544 else gMem.writeBM(addr, data[63:0], size, myPort);
545 } else {// 0x91-0x9F Reserved ERROR
546 ioSpaceAccess = 0;
547 }
548 }
549 4'hA: {// 0xA0-0xBF L2 CSR (handled by CCX directly and does not come to NCU) ERROR
550 PR_ERROR (CLASSNAMEQ, MON_ERR, psprintf ("T%d Bench ERROR FAIL: - L2 CSR address seen at NCU, this is bad! (addr=%0h (%0h),data=%0h,mask=%0h,read=%0h",thread,addr,addr[39:32],data,size,read));
551 }
552 4'hB: {// 0xA0-0xBF L2 CSR (handled by CCX directly and does not come to NCU) ERROR
553 PR_ERROR (CLASSNAMEQ, MON_ERR, psprintf ("T%d Bench ERROR FAIL: - L2 CSR address seen at NCU, this is bad! (addr=%0h (%0h),data=%0h,mask=%0h,read=%0h",thread,addr,addr[39:32],data,size,read));
554
555 }
556 4'hC: {// 0xC0-0xCF PCIE (64GB) / DMUPIO
557 if (read) data = gMem.read128(addr,myPort, 1);
558 else gMem.writeBM(addr, data[63:0], size, myPort);
559 }
560 4'hD: {// 0xD0-0xFE Reserved ERROR
561 ioSpaceAccess = 0;
562 }
563 4'hE: {// 0xD0-0xFE Reserved ERROR
564 ioSpaceAccess = 0;
565 }
566 4'hF: {// 0xD0-0xFE Reserved ERROR
567 if (addr[39:32] == 8'hFF) {// 0xFF SSI (boot ROM) ERROR on write
568 if (read) {
569 if (read) data = gMem.read128(addr,myPort, 1);
570 } else ioSpaceAccess = 0;
571 } else {// 0xD0-0xFE Reserved ERROR
572 ioSpaceAccess = 0;
573 }
574 }
575 } // case
576
577
578 // if +failNCUcheck fail the sim right now!
579 if (ioSpaceAccess == 0 && failNCUcheck == 1)
580 PR_ERROR (CLASSNAMEQ, MON_ERR, psprintf ("T%d Bench ERROR FAIL: - Attempt to access I/O address/ASI in a way that is NOT allowed. (addr=%0h (%0h),data=%0h,mask=%0h,read=%0h",thread,addr,addr[39:32],data,size,read));
581
582 // if +noNCUcheck, always return a happy value
583 // and (almost) always do the access
584 if (noNCUcheck) {
585 ioSpaceAccess = 1;
586 if (read == 1 && addr[39:32] !== 8'h82)
587 data = gMem.read128(addr,myPort, 1);
588 if (read == 0 && addr[39:32] !== 8'hFF)
589 gMem.writeBM(addr, data[63:0], size, myPort);
590 }
591
592 PR_INFO ("ioaccess", MON_INFO,
593 psprintf("err = %b Normal IO Register Access",
594 ioSpaceAccess));
595
596
597#endif
598#endif
599#endif
600}
601
602//----------------------------------------------------------
603// replicate data bytes across all data bytes depending on size.
604// big endian, so the high bit bytes replicate from high bit
605// end to low bit end.
606function reg[127:0] CLASSNAME::copyDataByte (reg [127:0] data,
607 reg [7:0] size,
608 reg [3:0] offset)
609{
610
611 reg [127:0] tmpData = 0;
612
613 // start with the addressed byte at byte 0
614 data = data << (8*offset);
615
616 case (size) {
617 8'h0: {// 1 byte
618 repeat (16) {
619 tmpData = tmpData >> 8; // seems backwards but works
620 tmpData[127:120] = data[127:120];
621 }
622 }
623 8'h1: {// 2 bytes
624 repeat (8) {
625 tmpData = tmpData >> 16;
626 tmpData[127:112] = data[127:112];
627 }
628 }
629 8'h2: {// 4 bytes
630 repeat (4) {
631 tmpData = tmpData >> 32;
632 tmpData[127:96] = data[127:96];
633 }
634 }
635 8'h3: {// 8 bytes
636 repeat (2) {
637 tmpData = tmpData >> 64;
638 tmpData[127:64] = data[127:64];
639 }
640 }
641 8'h4: {// 16 bytes
642 tmpData = data;
643 }
644
645 default: PR_ERROR("copyDataByte", MON_ERR, psprintf ("ERROR bad size=%b passed in.",size));
646
647 }
648
649 copyDataByte = tmpData;
650}
651
652
653
654
655// Evictions use 2 functions, evictAddr & evictVector.
656// "Eviction loop" code will call evictAddr to get address, then BFM will call
657// evictVector to get the vector and modify the shadow tag.
658// "Eviction loop" code will call task enqueueEvict in the correct bfm to
659// request the invalidate after evictAddr has been called.
660// The evict User Event that takes PA, will call task enqueueEvict in the
661// correct bfm to request the invalidate.
662
663
664//--------------------
665// Pick a random core and search for a line with a valid entry.
666// mem_index - itag 0..63, dtag 0..127
667// evict_index is normalized index between 0..31
668// used to search for tag in all lines in the group (aka L2 cache line)
669// returns a valid address.
670
671// Inputs:
672// core_enable = 8 bit vector, 1 bit per core
673// cid = N, to limit search to that core.
674// dCacheWeight = N to weight I/D caches. 100 % based
675//
676// Outputs:
677// found address if any, all F's otherwise.
678// cidUsed = a core that had the address
679function reg [63:0] CLASSNAME::evictAddr(reg [7:0] core_enable,
680 var reg [2:0] cidUsed,
681 reg [3:0] cid = 4'hf,
682 integer dCacheWeight = 60) // 100 % based
683{
684 reg evict=0; // =1, if valid entry found in the table
685 reg [6:0] mem_index=0; // raw index from tag table search
686 reg [28:0] evict_tag=0; // tag that is being evicted
687 reg [4:0] evict_index=0; // Normalized between 0..31
688 reg junk;
689 reg dCacheAddr = 0;
690
691#ifndef CCM_BENCH
692#ifndef FC_BENCH
693#ifndef FC_SCAN_BENCH
694
695 evictAddr = 64'hFFFFFFFFFFFFFFFF;
696 cidUsed = 0;
697
698 if (cid == 4'hf) {
699 // Pick cid out of the enabled cores.
700 // This runs in zero time so randCID is safe from other calls to randomize().
701 while (!core_enable[randCID]) {
702 void = this.randomize();
703 }
704 cidUsed = randCID;
705 } else {
706 // check the cid
707 cidUsed = cid;
708 if (!core_enable[cidUsed])
709 PR_ERROR("evict", MON_ERR,
710 psprintf (" BENCH ERROR - selected core not available!"));
711 }
712
713 randcase {
714 100-dCacheWeight: {
715 // Get raw index that has a valid entry
716 itag[cidUsed].search_tagmem(evict,mem_index); // set evict=1, if valid entry found
717 // found nothing
718 if (! evict) return;
719 // Normalize between 0..31
720 evict_index = mem_index / 2;
721 // Get the tag that will be evicted
722 itag[cidUsed].get_tag(mem_index,junk,evict_tag);
723 }
724 dCacheWeight: {
725 // Get raw index that has a valid entry
726 dtag[cidUsed].search_tagmem(evict,mem_index); // set evict=1, if valid entry found
727 // found nothing
728 if (! evict) return;
729 // Normalize between 0..31
730 evict_index = mem_index / 4;
731 // Get the tag that will be evicted
732 dtag[cidUsed].get_tag(mem_index,junk,evict_tag);
733 dCacheAddr = 1;
734 }
735 }
736
737 evictAddr = {evict_tag,evict_index,6'b0};
738
739 PR_INFO ("evict", MON_INFO,
740 psprintf("EVICTION evictAddr PA{[39:6],6'b0}=%h evict_tag(pa[39:11])=%h evict_index(pa[10:6])=%h core=%0d dCacheAddr=%0d",
741 evictAddr,evict_tag,evict_index,cidUsed,dCacheAddr));
742
743#endif
744#endif
745#endif
746
747}
748
749
750//----------------------------------------------------------
751// Evict a PA from the L1 cache in all cores that are enabled.
752// The value that is returned as evictVector has the format as defined
753// in the CCX packet spec as Vinv.
754//
755// Pass in address. Will check all enabled cores for hit at that address and return
756// an eviction vector for all matching/hitting cores.
757//
758// Inputs:
759// core_enable = 8 bit vector, 1 bit per core
760// evict_pa = address to evict
761// cpuId = CPU associated with evict_pa being cached
762// Output:
763// evictVector = 0, no entries to evict.
764// targets = cores that will be the target of the evict packet.
765function reg [127:0] CLASSNAME::evictVector(reg [7:0] core_enable,
766 reg [63:0] evict_pa,
767 reg [2:0] cpuId,
768 var reg [7:0] targets)
769{
770 reg evict=0; // 1, if valid entry found in the table
771 reg [6:0] mem_index=0; // raw index from tag table search
772 reg [28:0] evict_tag=0; // tag that is being evicted
773 reg [4:0] evict_index=0; // Normalized between 0..31
774 reg [3:0] dmatch=0;
775 reg [3:0] imatch=0,i;
776 reg [111:0] i_vect=0,d_vect=0,e_vect=0;
777
778#ifndef CCM_BENCH
779#ifndef FC_BENCH
780#ifndef FC_SCAN_BENCH
781
782 targets = 0;
783 evictVector = 0;
784
785 // Get index & tag from User argument
786 evict_tag = evict_pa[39:11];
787 evict_index = evict_pa[10:6];
788 mem_index = evict_pa[10:4]; // tag class array index
789
790
791 //--------------------
792 // If valid tag found in tag table, evict it in both itag & dtag
793
794 PR_INFO ("evict", MON_INFO,
795 psprintf("EVICTION evictVector PA{[39:6],6'b0}=%h evict_tag(pa[39:11])=%h evict_index(pa[10:6])=%h core=%0d mem_index(pa[10:4])=%h",
796 evict_pa,evict_tag,evict_index,cpuId,mem_index));
797
798 //--------------------
799 // If valid tag found in tag table, evict it in both itag & dtag
800 i_vect = 0;
801 d_vect = 0;
802 e_vect = 0;
803
804 // evict the pa in all cores L1 cache
805 for (i=0; i<=7; i=i+1) {
806 if (core_enable[i]) {
807 itag[i].evict_group(evict_tag, evict_index, i_vect);
808 dtag[i].evict_group(evict_tag, evict_index, d_vect);
809
810 if ((i_vect!=0)|(d_vect!=0)) {
811 targets[i] = 1'b1;
812 }
813
814 // Create invalidation vector that is returned in CPX pkt
815 e_vect = e_vect | i_vect | d_vect;
816 }
817 }
818
819
820 if (e_vect) {
821 //--------------------
822 // Debug messages
823
824 PR_INFO ("evict", MON_INFO,
825 psprintf("EVICTION evictVector PA[39:0]=%h tag=%h evict_index(pa[10:6])=%h mem_index(pa[10:4])=%h+",evict_pa,evict_tag,evict_index,mem_index));
826 PR_INFO ("evict", MON_INFO,
827 psprintf("EVICTION \taddr: 0x%12h 0x%12h 0x%12h 0x%12h", evict_pa+48,evict_pa+32, evict_pa+16, evict_pa));
828 PR_INFO ("evict", MON_INFO,
829 psprintf("EVICTION \titag: Vinv[111:88] = %h [87:56] = %h [55:32] = %h [31:0] = %h ",
830 i_vect[111:88],i_vect[87:56],i_vect[55:32],i_vect[31:0]));
831 PR_INFO ("evict", MON_INFO,
832 psprintf("EVICTION \tdtag: Vinv[111:88] = %h [87:56] = %h [55:32] = %h [31:0] = %h ",
833 d_vect[111:88],d_vect[87:56],d_vect[55:32],d_vect[31:0]));
834 PR_INFO ("evict", MON_INFO,
835 psprintf("EVICTION \t Vinv[111:88] = %h [87:56] = %h [55:32] = %h [31:0] = %h ",
836 e_vect[111:88],e_vect[87:56],e_vect[55:32],e_vect[31:0]));
837
838
839 // Create Vinv as defined in CCX packet spec
840 evictVector[127:117] = 11'b0;
841 evictVector[116:112] = evict_index;
842 evictVector[111:0] = e_vect;
843
844 } else {
845 // not an error because time elapsed and the L1 tags have changed!
846 }
847
848#endif
849#endif
850#endif
851
852}
853