Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: memArray.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 <baseUtilsClass.vrh> | |
39 | ||
40 | ||
41 | ////////////////////////////////////////////////////// | |
42 | // Stuff that Will change with data width | |
43 | ////////////////////////////////////////////////////// | |
44 | ||
45 | #define BYTE_LANES 8 | |
46 | ||
47 | // high order bits | |
48 | #define MEM_BM 7 | |
49 | #define MEM_DATA 63 | |
50 | #define MEM_ADDR 39 | |
51 | #define MEM_ECC 7 | |
52 | ||
53 | // low order bits | |
54 | // Array is 8 byte addressed, NOT byte addressed!!! | |
55 | #define MASK_EBW 64'hfffffffffffffff8 | |
56 | #define MASK_128 64'hfffffffffffffff0 | |
57 | #define MASK_512 64'hffffffffffffffc0 | |
58 | ||
59 | #define RAND_DATA {urandom(),urandom()} | |
60 | //#define DEFAULT_DATA 64'ha5a5a5a5a5a5a5a5 // breaks sparc model since it uses 0 | |
61 | #define DEFAULT_DATA 0 | |
62 | ||
63 | #define STD_DISP dbg | |
64 | ||
65 | //#define MEMARRAY_DEBUG 1 | |
66 | ||
67 | class MemArray { | |
68 | ||
69 | local reg [MEM_DATA:0] mainMem[]; // Array is 8 byte addressed, NOT byte addressed!!! | |
70 | local StandardDisplay dbg; | |
71 | local reg returnRandom = 0; // return random data for uninitialized address | |
72 | local reg shft; | |
73 | // general lock | |
74 | local integer semaLock; | |
75 | ||
76 | task new (reg shift=0, StandardDisplay dbgin, reg retnRandom=0) | |
77 | { | |
78 | this.dbg = dbgin; | |
79 | this.returnRandom = retnRandom; | |
80 | this.shft = shift; | |
81 | semaLock = alloc( SEMAPHORE, 0, 1, 1 ); | |
82 | } | |
83 | ||
84 | //---------------------------------------------------------- | |
85 | // read mem.image and store them into mainMem | |
86 | ||
87 | task loadMem (string mem_data, reg loadOnlyIOmem = 0, | |
88 | reg hash_on = 0, BaseUtils utils = null) | |
89 | { | |
90 | integer fdi; | |
91 | string line, val; | |
92 | reg [63:0] addr; | |
93 | reg [63:0] data; | |
94 | ||
95 | PR_NORMAL("loadMainMem", MON_NORMAL, | |
96 | psprintf("Loading mainMem from file = %s (loadOnlyIOmem=%0d)", mem_data, loadOnlyIOmem)); | |
97 | if (hash_on) { | |
98 | PR_NORMAL("loadMainMem", MON_NORMAL, | |
99 | psprintf("L2 Index Hash is ON")); | |
100 | } | |
101 | if (hash_on && utils == null) { | |
102 | PR_ERROR("loadMainMem", MON_ERROR, | |
103 | psprintf("L2 Index Hash is ON but BaseUtils handle is null! Need handle!")); | |
104 | } | |
105 | ||
106 | fdi = fopen (mem_data, "r"); | |
107 | if (fdi == 0) error ("Can't open input file\n"); | |
108 | ||
109 | while (1) { | |
110 | line = freadstr (fdi, RAWIN); // NTB needs RAWIN | |
111 | if (line == null) break; | |
112 | if(line.match("^\s*$"))continue; // empty line | |
113 | if(line.match("^\s*//.*"))continue; // 0 or more blanks then // (comment line) | |
114 | if(line.match("^@(\w+)")){ // @ in first column | |
115 | val = line.backref(0); | |
116 | addr = val.atohex(); | |
117 | if (shft) addr = addr >> 3; | |
118 | continue; // have address, now get data lines, if any | |
119 | } | |
120 | //while(line.match("\s*(\w+)")){ | |
121 | while(line.match("\s*([0-9a-fA-F]+)")){ // hex number | |
122 | val = line.backref(0); | |
123 | data = val.atohex(); | |
124 | if ((loadOnlyIOmem && addr[39]) || !loadOnlyIOmem) { | |
125 | // I/O Address are not hashed | |
126 | if (hash_on & (addr[39]==1'b0)) { | |
127 | mainMem[utils.hashpa(addr)] = data; | |
128 | PR_DEBUG("loadMainMem", MON_DEBUG, | |
129 | psprintf("Loading %x into %x", data, utils.hashpa(addr))); | |
130 | } else { | |
131 | mainMem[addr] = data; | |
132 | PR_DEBUG("loadMainMem", MON_DEBUG, | |
133 | psprintf("Loading %x into %x", data, addr)); | |
134 | } | |
135 | ||
136 | } | |
137 | line = line.postmatch(); | |
138 | if(shft)addr++; | |
139 | else addr += 8; | |
140 | } | |
141 | } | |
142 | fclose (fdi); | |
143 | printf(""); | |
144 | } | |
145 | ||
146 | //---------------------------------------------------------- | |
147 | // Dump Memory contents to specified file | |
148 | // (ported from N1) | |
149 | // | |
150 | task dump_mem(string filename, reg [MEM_ADDR:0] addr, integer num, reg shft) | |
151 | { | |
152 | integer fp, w_num; | |
153 | ||
154 | addr = addr & MASK_EBW; | |
155 | ||
156 | PR_NORMAL("dump_mem", MON_NORMAL, | |
157 | psprintf("Dumping mainMem to file = %s ", filename)); | |
158 | ||
159 | if (shft) { | |
160 | addr = addr >> 3; | |
161 | } | |
162 | fp = fopen (filename, "w"); | |
163 | w_num = 0; | |
164 | fprintf(fp, "=============================\n"); | |
165 | fprintf(fp, " ADDRESS : DATA\n"); | |
166 | fprintf(fp, "=============================\n"); | |
167 | while(w_num < num){ | |
168 | fprintf(fp, "%x : %x\n", addr, mainMem[addr]); | |
169 | if (shft) { | |
170 | addr = addr + 1; | |
171 | } else { | |
172 | addr = addr + 8; | |
173 | } | |
174 | w_num += 8; | |
175 | } | |
176 | fclose(fp); | |
177 | } | |
178 | ||
179 | //---------------------------------------------------------- | |
180 | // Write 64 bit word to memory | |
181 | task write_mem (reg [MEM_ADDR:0] addr, reg [MEM_DATA:0] data, integer id = 0) { | |
182 | semaphore_get( WAIT, semaLock , 1 ); | |
183 | addr = addr & MASK_EBW; | |
184 | mainMem[addr] = data; | |
185 | #ifdef MEMARRAY_DEBUG | |
186 | printf("%0d MemArray::write_mem [%0d] addr=%h, data=%h\n",get_cycle(),id,addr,data); | |
187 | dumpMem({addr[MEM_ADDR:6],6'b000000},8); // L2 block size | |
188 | #endif | |
189 | semaphore_put( semaLock , 1 ); | |
190 | } | |
191 | ||
192 | ||
193 | //---------------------------------------------------------- | |
194 | // Masked write | |
195 | task writeBM(bit [MEM_ADDR:0] addr, | |
196 | bit [MEM_DATA:0] data, | |
197 | bit [MEM_BM:0] byteMask, | |
198 | integer id = 0) { | |
199 | ||
200 | bit [MEM_DATA:0] tmpData, mem_out, memMask, tmp; | |
201 | integer i; | |
202 | ||
203 | semaphore_get( WAIT, semaLock , 1 ); | |
204 | addr = addr & MASK_EBW; | |
205 | ||
206 | // build up a mask as wide as the data. | |
207 | // if mask is "all bytes" then call the faster write() task. | |
208 | if (byteMask == ~0) | |
209 | { | |
210 | semaphore_put( semaLock , 1 ); | |
211 | this.write_mem(addr,data,id); | |
212 | return; | |
213 | } | |
214 | else | |
215 | { | |
216 | memMask = 0; | |
217 | for (i = MEM_BM ; i >= 0 ; i--) | |
218 | { | |
219 | if (byteMask[i] == 1) memMask = {memMask, 8'hFF}; | |
220 | else memMask = {memMask, 8'h00}; | |
221 | } | |
222 | } | |
223 | ||
224 | if (assoc_index(CHECK,mainMem,addr)) | |
225 | { | |
226 | tmp = mainMem[addr]; | |
227 | mem_out = tmp[MEM_DATA:0]; | |
228 | } | |
229 | else // adress never written | |
230 | { | |
231 | if (returnRandom) mem_out = RAND_DATA; | |
232 | else mem_out = 64'h0; | |
233 | } | |
234 | ||
235 | // merge in selected data bytes | |
236 | tmpData = ( mem_out & ~memMask ) | ( data & memMask ) ; | |
237 | // update array | |
238 | mainMem[ addr ] = tmpData; | |
239 | #ifdef MEMARRAY_DEBUG | |
240 | printf("%0d MemArray::writeBM [%0d] addr=%h, data=%h, mask=%h\n",get_cycle(),id,addr,data,byteMask); | |
241 | dumpMem({addr[MEM_ADDR:6],6'b000000},8); // L2 block size | |
242 | #endif | |
243 | ||
244 | semaphore_put( semaLock , 1 ); | |
245 | ||
246 | } | |
247 | ||
248 | //---------------------------------------------------------- | |
249 | // Write 512 bit block to memory | |
250 | task write512(reg [MEM_ADDR:0] addr, reg [511:0] data, integer id=0, reg revEndian=0) { | |
251 | integer i,j; | |
252 | ||
253 | addr = addr & MASK_512; | |
254 | ||
255 | if (revEndian) { | |
256 | for (i=0,j=7;i<8;i++,j--) { | |
257 | mainMem[addr+(i*8)] = data[(j*64)+63:j*64]; | |
258 | } | |
259 | } else { | |
260 | for (i=0;i<8;i++) { | |
261 | mainMem[addr+(i*8)] = data[(i*64)+63:i*64]; | |
262 | } | |
263 | } | |
264 | #ifdef MEMARRAY_DEBUG | |
265 | printf("%0d MemArray::write512 [%0d] addr=%h, data=%h, revEndian=%0b\n",get_cycle(),id,addr,data,revEndian); | |
266 | dumpMem({addr[MEM_ADDR:6],6'b000000},8); // L2 block size | |
267 | #endif | |
268 | ||
269 | } | |
270 | ||
271 | //---------------------------------------------------------- | |
272 | // Write 128 bit block to memory | |
273 | task write128(reg [MEM_ADDR:0] addr, reg [127:0] data, integer id=0, reg revEndian=0) { | |
274 | integer i,j; | |
275 | ||
276 | addr = addr & MASK_128; | |
277 | ||
278 | if (revEndian) { | |
279 | for (i=0,j=1;i<2;i++,j--) { | |
280 | mainMem[addr+(i*8)] = data[(j*64)+63:j*64]; | |
281 | } | |
282 | } else { | |
283 | for (i=0;i<2;i++) { | |
284 | mainMem[addr+(i*8)] = data[(i*64)+63:i*64]; | |
285 | } | |
286 | } | |
287 | #ifdef MEMARRAY_DEBUG | |
288 | printf("%0d MemArray::write128 [%0d] addr=%h, data=%h, revEndian=%0b\n",get_cycle(),id,addr,data,revEndian); | |
289 | dumpMem({addr[MEM_ADDR:6],6'b000000},8); // L2 block size | |
290 | #endif | |
291 | ||
292 | } | |
293 | ||
294 | ||
295 | //---------------------------------------------------------- | |
296 | // Read 64 bit word from memory | |
297 | function reg [MEM_DATA:0] read_mem (reg [MEM_ADDR:0] addr,integer id=0, reg uninitWarn=0) { | |
298 | ||
299 | addr = addr & MASK_EBW; | |
300 | ||
301 | // If memory location has not been initialized, | |
302 | // return all 0's or random data | |
303 | if (assoc_index(CHECK,mainMem,addr)) { | |
304 | read_mem = mainMem[addr]; | |
305 | } else { | |
306 | if (returnRandom) read_mem = RAND_DATA; | |
307 | else read_mem = DEFAULT_DATA; | |
308 | // if (! addr[39]) PR_INFO("memArray", MON_INFO, | |
309 | // psprintf("WARNING - Access to uninitialized address(%h) in L2 memory ",addr)); | |
310 | } | |
311 | ||
312 | #ifdef MEMARRAY_DEBUG | |
313 | printf("%0d MemArray::read_mem [%0d] addr=%h, data=%h\n",get_cycle(),id,addr,read_mem); | |
314 | dumpMem({addr[MEM_ADDR:6],6'b000000},8); // L2 block size | |
315 | #endif | |
316 | ||
317 | } | |
318 | ||
319 | // Read 512 bit block from memory | |
320 | function reg [511:0] read512 (reg [MEM_ADDR:0] addr, integer id=0, reg revEndian=0, reg uninitWarn=0) { | |
321 | integer i,j; | |
322 | read512 = 0; | |
323 | ||
324 | addr = addr & MASK_512; | |
325 | ||
326 | if (revEndian) { | |
327 | for (i=0,j=7;i<8;i++,j--) { | |
328 | if (assoc_index(CHECK,mainMem,addr+(i*8))) { | |
329 | read512[(j*64)+63:j*64] = mainMem[addr+(i*8)]; | |
330 | } else { | |
331 | if (returnRandom) read512[(j*64)+63:j*64] = RAND_DATA; | |
332 | else read512[(j*64)+63:j*64] = DEFAULT_DATA; | |
333 | // if (! addr[39]) PR_INFO("memArray", MON_INFO, | |
334 | // psprintf("WARNING - Access to uninitialized address(%h) in L2 memory ",addr)); | |
335 | } | |
336 | } | |
337 | } else { | |
338 | for (i=0;i<8;i++) { | |
339 | if (assoc_index(CHECK,mainMem,addr+(i*8))) { | |
340 | read512[(i*64)+63:i*64] = mainMem[addr+(i*8)]; | |
341 | } else { | |
342 | if (returnRandom) read512[(i*64)+63:i*64] = RAND_DATA; | |
343 | else read512[(i*64)+63:i*64] = DEFAULT_DATA; | |
344 | // if (! addr[39]) PR_INFO("memArray", MON_INFO, | |
345 | // psprintf("WARNING - Access to uninitialized address(%h) in L2 memory ",addr)); | |
346 | } | |
347 | } | |
348 | } | |
349 | #ifdef MEMARRAY_DEBUG | |
350 | printf("%0d MemArray::read512 [%0d] addr=%h, data=%h, revEndian=%0b\n",get_cycle(),id,addr,read512,revEndian); | |
351 | dumpMem({addr[MEM_ADDR:6],6'b000000},8); // L2 block size | |
352 | #endif | |
353 | } | |
354 | ||
355 | // Read 128 bit block from memory | |
356 | function reg [127:0] read128 (reg [MEM_ADDR:0] addr, integer id=0, reg revEndian=0, reg uninitWarn=0) { | |
357 | integer i,j; | |
358 | read128 = 0; | |
359 | ||
360 | addr = addr & MASK_128; | |
361 | ||
362 | if (revEndian) { | |
363 | for (i=0,j=1;i<2;i++,j--) { | |
364 | if (assoc_index(CHECK,mainMem,addr+(i*8))) { | |
365 | read128[(j*64)+63:j*64] = mainMem[addr+(i*8)]; | |
366 | } else { | |
367 | if (returnRandom) read128[(j*64)+63:j*64] = RAND_DATA; | |
368 | else read128[(j*64)+63:j*64] = DEFAULT_DATA; | |
369 | // if (! addr[39]) PR_INFO("memArray", MON_INFO, | |
370 | // psprintf("WARNING - Access to uninitialized address(%h) in L2 memory ",addr)); | |
371 | } | |
372 | } | |
373 | } else { | |
374 | for (i=0;i<2;i++) { | |
375 | if (assoc_index(CHECK,mainMem,addr+(i*8))) { | |
376 | read128[(i*64)+63:i*64] = mainMem[addr+(i*8)]; | |
377 | } else { | |
378 | if (returnRandom) read128[(i*64)+63:i*64] = RAND_DATA; | |
379 | else read128[(i*64)+63:i*64] = DEFAULT_DATA; | |
380 | // if (! addr[39]) PR_INFO("memArray", MON_INFO, | |
381 | // psprintf("WARNING - Access to uninitialized address(%h) in L2 memory ",addr)); | |
382 | } | |
383 | } | |
384 | } | |
385 | #ifdef MEMARRAY_DEBUG | |
386 | printf("%0d MemArray::read128 [%0d] addr=%h, data=%h, revEndian=%0b\n",get_cycle(),id,addr,read128,revEndian); | |
387 | dumpMem({addr[MEM_ADDR:6],6'b000000},8); // L2 block size | |
388 | #endif | |
389 | } | |
390 | ||
391 | ||
392 | ||
393 | // free contents. Use either start & end address OR | |
394 | // start address and amount. Amount is number of BYTES | |
395 | task freeMem(bit [MEM_ADDR:0] start, | |
396 | bit [MEM_ADDR:0] ending=0, | |
397 | integer amount=0) | |
398 | { | |
399 | ||
400 | integer success; | |
401 | integer remaining; | |
402 | bit [MEM_ADDR:0] tmpaddr, index; | |
403 | ||
404 | ||
405 | semaphore_get( WAIT, semaLock , 1 ); | |
406 | start = start & MASK_EBW; | |
407 | ending = ending & MASK_EBW; | |
408 | ||
409 | if (amount & ending) | |
410 | { | |
411 | error("ERROR - freeMem was used incorrectly!!!\n"); | |
412 | } | |
413 | ||
414 | if (amount) { | |
415 | // adjust amount in bytes to be amount in "memory array width" lines. | |
416 | amount = amount + start[2:0]; // take offset into account 8 byte word based | |
417 | if (amount % BYTE_LANES) amount = amount/BYTE_LANES + 1; | |
418 | else amount = amount/BYTE_LANES; | |
419 | ||
420 | index = start; | |
421 | remaining = amount; | |
422 | while (remaining) | |
423 | { | |
424 | assoc_index (DELETE, mainMem, index); | |
425 | success = assoc_index (NEXT, mainMem, index); | |
426 | if (success == 0 || index >= start+amount) break; | |
427 | remaining--; | |
428 | } | |
429 | ||
430 | } else { // user gave ending address | |
431 | index = start; | |
432 | ending = ending; | |
433 | while (index <= ending) | |
434 | { | |
435 | assoc_index (DELETE, mainMem, index); | |
436 | success = assoc_index (NEXT, mainMem, index); | |
437 | // if unsuccessful we need to break out | |
438 | if (success == 0 || index >= ending) break; | |
439 | } | |
440 | } | |
441 | semaphore_put( semaLock , 1 ); | |
442 | } | |
443 | ||
444 | ||
445 | // Dump a range of memory. | |
446 | // amount is in array widths/elements. | |
447 | task dumpMem(bit [MEM_ADDR:0] addr, | |
448 | integer amount) | |
449 | ||
450 | { | |
451 | bit [MEM_DATA:0] data; | |
452 | integer i,tmp; | |
453 | bit [MEM_ADDR:0] word_size_mask=BYTE_LANES-1; // 4-1=3 | |
454 | ||
455 | addr = addr & MASK_EBW; | |
456 | ||
457 | printf("%0d dumpMem: dumping memory at 0x%h for %0d Addresses :\n",get_cycle(), addr,amount); | |
458 | ||
459 | // adjust amount in bytes to be amount in "memory array width" lines. | |
460 | //amount = amount + start[2:0]; | |
461 | //if (amount % 8) amount = amount/8 + 1; | |
462 | //else amount = amount/8; | |
463 | ||
464 | ||
465 | for (i = 1 ; i <= amount ; i++) { | |
466 | if (assoc_index(CHECK,mainMem,addr)) | |
467 | printf(" Addr = 0x%h, Data = 0x%h\n",addr,mainMem[addr]); | |
468 | else | |
469 | printf(" Addr = 0x%h, Data = uninitialized addr\n",addr); | |
470 | addr += BYTE_LANES; | |
471 | } | |
472 | ||
473 | printf("%0d dumpMem: finished dumping memory.\n\n",get_cycle()); | |
474 | ||
475 | } | |
476 | ||
477 | // for debug only | |
478 | task dumpArray() | |
479 | { | |
480 | ||
481 | bit [MEM_ADDR:0] index=0; | |
482 | ||
483 | printf("\n"); | |
484 | printf("%0d dumpArray: \n", get_cycle()); | |
485 | ||
486 | if ( assoc_index(FIRST, mainMem, index)) | |
487 | printf(" index=0x%h, data=0x%h \n", index, mainMem[index]); | |
488 | else return; | |
489 | ||
490 | while ( assoc_index(NEXT, mainMem, index) ) | |
491 | printf(" index=0x%h, data=0x%h \n", index, mainMem[index]); | |
492 | ||
493 | printf("\n"); | |
494 | } | |
495 | ||
496 | } |