// ========== Copyright Header Begin ========================================== // // OpenSPARC T2 Processor File: memArray.vr // Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved // 4150 Network Circle, Santa Clara, California 95054, U.S.A. // // * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; version 2 of the License. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // For the avoidance of doubt, and except that if any non-GPL license // choice is available it will apply instead, Sun elects to use only // the General Public License version 2 (GPLv2) at this time for any // software where a choice of GPL license versions is made // available with the language indicating that GPLv2 or any later version // may be used, or where a choice of which version of the GPL is applied is // otherwise unspecified. // // Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, // CA 95054 USA or visit www.sun.com if you need additional information or // have any questions. // // ========== Copyright Header End ============================================ #include #include "std_display_defines.vri" #include "std_display_class.vrh" #include ////////////////////////////////////////////////////// // Stuff that Will change with data width ////////////////////////////////////////////////////// #define BYTE_LANES 8 // high order bits #define MEM_BM 7 #define MEM_DATA 63 #define MEM_ADDR 39 #define MEM_ECC 7 // low order bits // Array is 8 byte addressed, NOT byte addressed!!! #define MASK_EBW 64'hfffffffffffffff8 #define MASK_128 64'hfffffffffffffff0 #define MASK_512 64'hffffffffffffffc0 #define RAND_DATA {urandom(),urandom()} //#define DEFAULT_DATA 64'ha5a5a5a5a5a5a5a5 // breaks sparc model since it uses 0 #define DEFAULT_DATA 0 #define STD_DISP dbg //#define MEMARRAY_DEBUG 1 class MemArray { local reg [MEM_DATA:0] mainMem[]; // Array is 8 byte addressed, NOT byte addressed!!! local StandardDisplay dbg; local reg returnRandom = 0; // return random data for uninitialized address local reg shft; // general lock local integer semaLock; task new (reg shift=0, StandardDisplay dbgin, reg retnRandom=0) { this.dbg = dbgin; this.returnRandom = retnRandom; this.shft = shift; semaLock = alloc( SEMAPHORE, 0, 1, 1 ); } //---------------------------------------------------------- // read mem.image and store them into mainMem task loadMem (string mem_data, reg loadOnlyIOmem = 0, reg hash_on = 0, BaseUtils utils = null) { integer fdi; string line, val; reg [63:0] addr; reg [63:0] data; PR_NORMAL("loadMainMem", MON_NORMAL, psprintf("Loading mainMem from file = %s (loadOnlyIOmem=%0d)", mem_data, loadOnlyIOmem)); if (hash_on) { PR_NORMAL("loadMainMem", MON_NORMAL, psprintf("L2 Index Hash is ON")); } if (hash_on && utils == null) { PR_ERROR("loadMainMem", MON_ERROR, psprintf("L2 Index Hash is ON but BaseUtils handle is null! Need handle!")); } fdi = fopen (mem_data, "r"); if (fdi == 0) error ("Can't open input file\n"); while (1) { line = freadstr (fdi, RAWIN); // NTB needs RAWIN if (line == null) break; if(line.match("^\s*$"))continue; // empty line if(line.match("^\s*//.*"))continue; // 0 or more blanks then // (comment line) if(line.match("^@(\w+)")){ // @ in first column val = line.backref(0); addr = val.atohex(); if (shft) addr = addr >> 3; continue; // have address, now get data lines, if any } //while(line.match("\s*(\w+)")){ while(line.match("\s*([0-9a-fA-F]+)")){ // hex number val = line.backref(0); data = val.atohex(); if ((loadOnlyIOmem && addr[39]) || !loadOnlyIOmem) { // I/O Address are not hashed if (hash_on & (addr[39]==1'b0)) { mainMem[utils.hashpa(addr)] = data; PR_DEBUG("loadMainMem", MON_DEBUG, psprintf("Loading %x into %x", data, utils.hashpa(addr))); } else { mainMem[addr] = data; PR_DEBUG("loadMainMem", MON_DEBUG, psprintf("Loading %x into %x", data, addr)); } } line = line.postmatch(); if(shft)addr++; else addr += 8; } } fclose (fdi); printf(""); } //---------------------------------------------------------- // Dump Memory contents to specified file // (ported from N1) // task dump_mem(string filename, reg [MEM_ADDR:0] addr, integer num, reg shft) { integer fp, w_num; addr = addr & MASK_EBW; PR_NORMAL("dump_mem", MON_NORMAL, psprintf("Dumping mainMem to file = %s ", filename)); if (shft) { addr = addr >> 3; } fp = fopen (filename, "w"); w_num = 0; fprintf(fp, "=============================\n"); fprintf(fp, " ADDRESS : DATA\n"); fprintf(fp, "=============================\n"); while(w_num < num){ fprintf(fp, "%x : %x\n", addr, mainMem[addr]); if (shft) { addr = addr + 1; } else { addr = addr + 8; } w_num += 8; } fclose(fp); } //---------------------------------------------------------- // Write 64 bit word to memory task write_mem (reg [MEM_ADDR:0] addr, reg [MEM_DATA:0] data, integer id = 0) { semaphore_get( WAIT, semaLock , 1 ); addr = addr & MASK_EBW; mainMem[addr] = data; #ifdef MEMARRAY_DEBUG printf("%0d MemArray::write_mem [%0d] addr=%h, data=%h\n",get_cycle(),id,addr,data); dumpMem({addr[MEM_ADDR:6],6'b000000},8); // L2 block size #endif semaphore_put( semaLock , 1 ); } //---------------------------------------------------------- // Masked write task writeBM(bit [MEM_ADDR:0] addr, bit [MEM_DATA:0] data, bit [MEM_BM:0] byteMask, integer id = 0) { bit [MEM_DATA:0] tmpData, mem_out, memMask, tmp; integer i; semaphore_get( WAIT, semaLock , 1 ); addr = addr & MASK_EBW; // build up a mask as wide as the data. // if mask is "all bytes" then call the faster write() task. if (byteMask == ~0) { semaphore_put( semaLock , 1 ); this.write_mem(addr,data,id); return; } else { memMask = 0; for (i = MEM_BM ; i >= 0 ; i--) { if (byteMask[i] == 1) memMask = {memMask, 8'hFF}; else memMask = {memMask, 8'h00}; } } if (assoc_index(CHECK,mainMem,addr)) { tmp = mainMem[addr]; mem_out = tmp[MEM_DATA:0]; } else // adress never written { if (returnRandom) mem_out = RAND_DATA; else mem_out = 64'h0; } // merge in selected data bytes tmpData = ( mem_out & ~memMask ) | ( data & memMask ) ; // update array mainMem[ addr ] = tmpData; #ifdef MEMARRAY_DEBUG printf("%0d MemArray::writeBM [%0d] addr=%h, data=%h, mask=%h\n",get_cycle(),id,addr,data,byteMask); dumpMem({addr[MEM_ADDR:6],6'b000000},8); // L2 block size #endif semaphore_put( semaLock , 1 ); } //---------------------------------------------------------- // Write 512 bit block to memory task write512(reg [MEM_ADDR:0] addr, reg [511:0] data, integer id=0, reg revEndian=0) { integer i,j; addr = addr & MASK_512; if (revEndian) { for (i=0,j=7;i<8;i++,j--) { mainMem[addr+(i*8)] = data[(j*64)+63:j*64]; } } else { for (i=0;i<8;i++) { mainMem[addr+(i*8)] = data[(i*64)+63:i*64]; } } #ifdef MEMARRAY_DEBUG printf("%0d MemArray::write512 [%0d] addr=%h, data=%h, revEndian=%0b\n",get_cycle(),id,addr,data,revEndian); dumpMem({addr[MEM_ADDR:6],6'b000000},8); // L2 block size #endif } //---------------------------------------------------------- // Write 128 bit block to memory task write128(reg [MEM_ADDR:0] addr, reg [127:0] data, integer id=0, reg revEndian=0) { integer i,j; addr = addr & MASK_128; if (revEndian) { for (i=0,j=1;i<2;i++,j--) { mainMem[addr+(i*8)] = data[(j*64)+63:j*64]; } } else { for (i=0;i<2;i++) { mainMem[addr+(i*8)] = data[(i*64)+63:i*64]; } } #ifdef MEMARRAY_DEBUG printf("%0d MemArray::write128 [%0d] addr=%h, data=%h, revEndian=%0b\n",get_cycle(),id,addr,data,revEndian); dumpMem({addr[MEM_ADDR:6],6'b000000},8); // L2 block size #endif } //---------------------------------------------------------- // Read 64 bit word from memory function reg [MEM_DATA:0] read_mem (reg [MEM_ADDR:0] addr,integer id=0, reg uninitWarn=0) { addr = addr & MASK_EBW; // If memory location has not been initialized, // return all 0's or random data if (assoc_index(CHECK,mainMem,addr)) { read_mem = mainMem[addr]; } else { if (returnRandom) read_mem = RAND_DATA; else read_mem = DEFAULT_DATA; // if (! addr[39]) PR_INFO("memArray", MON_INFO, // psprintf("WARNING - Access to uninitialized address(%h) in L2 memory ",addr)); } #ifdef MEMARRAY_DEBUG printf("%0d MemArray::read_mem [%0d] addr=%h, data=%h\n",get_cycle(),id,addr,read_mem); dumpMem({addr[MEM_ADDR:6],6'b000000},8); // L2 block size #endif } // Read 512 bit block from memory function reg [511:0] read512 (reg [MEM_ADDR:0] addr, integer id=0, reg revEndian=0, reg uninitWarn=0) { integer i,j; read512 = 0; addr = addr & MASK_512; if (revEndian) { for (i=0,j=7;i<8;i++,j--) { if (assoc_index(CHECK,mainMem,addr+(i*8))) { read512[(j*64)+63:j*64] = mainMem[addr+(i*8)]; } else { if (returnRandom) read512[(j*64)+63:j*64] = RAND_DATA; else read512[(j*64)+63:j*64] = DEFAULT_DATA; // if (! addr[39]) PR_INFO("memArray", MON_INFO, // psprintf("WARNING - Access to uninitialized address(%h) in L2 memory ",addr)); } } } else { for (i=0;i<8;i++) { if (assoc_index(CHECK,mainMem,addr+(i*8))) { read512[(i*64)+63:i*64] = mainMem[addr+(i*8)]; } else { if (returnRandom) read512[(i*64)+63:i*64] = RAND_DATA; else read512[(i*64)+63:i*64] = DEFAULT_DATA; // if (! addr[39]) PR_INFO("memArray", MON_INFO, // psprintf("WARNING - Access to uninitialized address(%h) in L2 memory ",addr)); } } } #ifdef MEMARRAY_DEBUG printf("%0d MemArray::read512 [%0d] addr=%h, data=%h, revEndian=%0b\n",get_cycle(),id,addr,read512,revEndian); dumpMem({addr[MEM_ADDR:6],6'b000000},8); // L2 block size #endif } // Read 128 bit block from memory function reg [127:0] read128 (reg [MEM_ADDR:0] addr, integer id=0, reg revEndian=0, reg uninitWarn=0) { integer i,j; read128 = 0; addr = addr & MASK_128; if (revEndian) { for (i=0,j=1;i<2;i++,j--) { if (assoc_index(CHECK,mainMem,addr+(i*8))) { read128[(j*64)+63:j*64] = mainMem[addr+(i*8)]; } else { if (returnRandom) read128[(j*64)+63:j*64] = RAND_DATA; else read128[(j*64)+63:j*64] = DEFAULT_DATA; // if (! addr[39]) PR_INFO("memArray", MON_INFO, // psprintf("WARNING - Access to uninitialized address(%h) in L2 memory ",addr)); } } } else { for (i=0;i<2;i++) { if (assoc_index(CHECK,mainMem,addr+(i*8))) { read128[(i*64)+63:i*64] = mainMem[addr+(i*8)]; } else { if (returnRandom) read128[(i*64)+63:i*64] = RAND_DATA; else read128[(i*64)+63:i*64] = DEFAULT_DATA; // if (! addr[39]) PR_INFO("memArray", MON_INFO, // psprintf("WARNING - Access to uninitialized address(%h) in L2 memory ",addr)); } } } #ifdef MEMARRAY_DEBUG printf("%0d MemArray::read128 [%0d] addr=%h, data=%h, revEndian=%0b\n",get_cycle(),id,addr,read128,revEndian); dumpMem({addr[MEM_ADDR:6],6'b000000},8); // L2 block size #endif } // free contents. Use either start & end address OR // start address and amount. Amount is number of BYTES task freeMem(bit [MEM_ADDR:0] start, bit [MEM_ADDR:0] ending=0, integer amount=0) { integer success; integer remaining; bit [MEM_ADDR:0] tmpaddr, index; semaphore_get( WAIT, semaLock , 1 ); start = start & MASK_EBW; ending = ending & MASK_EBW; if (amount & ending) { error("ERROR - freeMem was used incorrectly!!!\n"); } if (amount) { // adjust amount in bytes to be amount in "memory array width" lines. amount = amount + start[2:0]; // take offset into account 8 byte word based if (amount % BYTE_LANES) amount = amount/BYTE_LANES + 1; else amount = amount/BYTE_LANES; index = start; remaining = amount; while (remaining) { assoc_index (DELETE, mainMem, index); success = assoc_index (NEXT, mainMem, index); if (success == 0 || index >= start+amount) break; remaining--; } } else { // user gave ending address index = start; ending = ending; while (index <= ending) { assoc_index (DELETE, mainMem, index); success = assoc_index (NEXT, mainMem, index); // if unsuccessful we need to break out if (success == 0 || index >= ending) break; } } semaphore_put( semaLock , 1 ); } // Dump a range of memory. // amount is in array widths/elements. task dumpMem(bit [MEM_ADDR:0] addr, integer amount) { bit [MEM_DATA:0] data; integer i,tmp; bit [MEM_ADDR:0] word_size_mask=BYTE_LANES-1; // 4-1=3 addr = addr & MASK_EBW; printf("%0d dumpMem: dumping memory at 0x%h for %0d Addresses :\n",get_cycle(), addr,amount); // adjust amount in bytes to be amount in "memory array width" lines. //amount = amount + start[2:0]; //if (amount % 8) amount = amount/8 + 1; //else amount = amount/8; for (i = 1 ; i <= amount ; i++) { if (assoc_index(CHECK,mainMem,addr)) printf(" Addr = 0x%h, Data = 0x%h\n",addr,mainMem[addr]); else printf(" Addr = 0x%h, Data = uninitialized addr\n",addr); addr += BYTE_LANES; } printf("%0d dumpMem: finished dumping memory.\n\n",get_cycle()); } // for debug only task dumpArray() { bit [MEM_ADDR:0] index=0; printf("\n"); printf("%0d dumpArray: \n", get_cycle()); if ( assoc_index(FIRST, mainMem, index)) printf(" index=0x%h, data=0x%h \n", index, mainMem[index]); else return; while ( assoc_index(NEXT, mainMem, index) ) printf(" index=0x%h, data=0x%h \n", index, mainMem[index]); printf("\n"); } }