Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / cpus / vonk / ss / lib / ras / src / SS_CKMemory.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: SS_CKMemory.cc
// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
//
// The above named program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License version 2 as published by the Free Software Foundation.
//
// The above named 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 work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
//
// ========== Copyright Header End ============================================
#include "SS_CKMemory.h"
SS_CKMemory::SS_CKMemory(SS_Memory *mem)/*{{{*/
:ss_mem(mem),
debug_CK(getenv("CK_CHIPKILL_DEBUG") != NULL)
{
}
/*}}}*/
SS_CKMemory::~SS_CKMemory()/*{{{*/
{
}
/*}}}*/
uint64_t SS_CKMemory::ras_ld_buf( uint64_t addr, uint_t size )/*{{{*/
{
mem_xact.paddr(addr);
mem_xact.size(size);
mem_xact.access(MemoryTransaction::READ);
mem_xact.referenceType(MemoryTransaction::DATA);
read_dram_error_corrected(mem_xact);
return mem_xact.getData();
}
/*}}}*/
void SS_CKMemory::ras_ld( uint64_t addr, uint_t size, uint64_t* data )/*{{{*/
{
mem_xact.paddr(addr);
mem_xact.size(size);
mem_xact.access(MemoryTransaction::READ);
mem_xact.referenceType(MemoryTransaction::DATA);
read_dram_error_corrected(mem_xact);
for (uint_t i=0; size; i++, size -= 8)
data[i]= mem_xact.getData(i);
}
/*}}}*/
uint32_t SS_CKMemory::fetch32( uint64_t addr )/*{{{*/
{
mem_xact.paddr(addr);
mem_xact.size(4);
mem_xact.access(MemoryTransaction::READ);
mem_xact.referenceType(MemoryTransaction::INSTR);
read_dram_error_corrected(mem_xact);
return mem_xact.getData();
}
/*}}}*/
void SS_CKMemory::fetch256( uint64_t addr, uint64_t data[4] )/*{{{*/
{
mem_xact.paddr(addr);
mem_xact.size(32);
mem_xact.access(MemoryTransaction::READ);
mem_xact.referenceType(MemoryTransaction::INSTR);
read_dram_error_corrected(mem_xact);
uint_t size = 32;
for (uint_t i=0; size; i++, size -= 8)
data[i]= mem_xact.getData(i);
}
/*}}}*/
void SS_CKMemory::fetch512( uint64_t addr, uint64_t data[8] )/*{{{*/
{
mem_xact.paddr(addr);
mem_xact.size(64);
mem_xact.access(MemoryTransaction::READ);
mem_xact.referenceType(MemoryTransaction::INSTR);
read_dram_error_corrected(mem_xact);
uint_t size = 64;
for (uint_t i=0; size; i++, size -= 8)
data[i]= mem_xact.getData(i);
}
/*}}}*/
void SS_CKMemory::st8( uint64_t addr, uint8_t data )/*{{{*/
{
ss_mem->st8(addr,data);
}
/*}}}*/
void SS_CKMemory::st16( uint64_t addr, uint16_t data )/*{{{*/
{
ss_mem->st16(addr,data);
}
/*}}}*/
void SS_CKMemory::st32( uint64_t addr, uint32_t data )/*{{{*/
{
ss_mem->st32(addr,data);
}
/*}}}*/
void SS_CKMemory::st64( uint64_t addr, uint64_t data )/*{{{*/
{
ss_mem->st64(addr,data);
}
/*}}}*/
void SS_CKMemory::st128( uint64_t addr, uint64_t data[2] )/*{{{*/
{
ss_mem->st128(addr,data);
}
/*}}}*/
void SS_CKMemory::st512( uint64_t addr, uint64_t data[8] )/*{{{*/
{
ss_mem->st512(addr,data);
}
/*}}}*/
uint8_t SS_CKMemory::ld8u ( uint64_t addr )/*{{{*/
{
return ras_ld_buf(addr,1);
}
/*}}}*/
int8_t SS_CKMemory::ld8s( uint64_t addr )/*{{{*/
{
return ras_ld_buf(addr,1);
}
/*}}}*/
uint16_t SS_CKMemory::ld16u( uint64_t addr )/*{{{*/
{
return ras_ld_buf(addr,2);
}
/*}}}*/
int16_t SS_CKMemory::ld16s( uint64_t addr )/*{{{*/
{
return ras_ld_buf(addr,2);
}
/*}}}*/
uint32_t SS_CKMemory::ld32u( uint64_t addr )/*{{{*/
{
return ras_ld_buf(addr,4);
}
/*}}}*/
int32_t SS_CKMemory::ld32s( uint64_t addr )/*{{{*/
{
return ras_ld_buf(addr,4);
}
/*}}}*/
uint64_t SS_CKMemory::ld64( uint64_t addr )/*{{{*/
{
return ras_ld_buf(addr,8);
}
/*}}}*/
void SS_CKMemory::ld128( uint64_t addr, uint64_t data[2] ) /*{{{*/
{
ras_ld(addr,16,data);
}
/*}}}*/
void SS_CKMemory::ld256( uint64_t addr, uint64_t data[4] )/*{{{*/
{
ras_ld(addr,32,data);
}
/*}}}*/
void SS_CKMemory::ld512( uint64_t addr, uint64_t data[8] )/*{{{*/
{
ras_ld(addr,64,data);
}
/*}}}*/
void SS_CKMemory::st64partial( uint64_t addr, uint64_t data, uint64_t mask ) /*{{{*/
{
ss_mem->st64partial(addr,data,mask);
}
/*}}}*/
void SS_CKMemory::ld128atomic( uint64_t addr, uint64_t data[2] )/*{{{*/
{
ras_ld(addr,16,data);
}
/*}}}*/
uint8_t SS_CKMemory::ldstub( uint64_t addr )/*{{{*/
{
mem_xact.referenceType(MemoryTransaction::DATA);
mem_xact.paddr(addr);
mem_xact.size(1);
mem_xact.access(MemoryTransaction::READ|MemoryTransaction::ATOMIC);
read_dram_error_corrected(mem_xact);
uint64_t data = mem_xact.getData();
ss_mem->poke8(addr,0xff);
return data;
}
/*}}}*/
uint32_t SS_CKMemory::swap( uint64_t addr, uint32_t rd )/*{{{*/
{
mem_xact.referenceType(MemoryTransaction::DATA);
mem_xact.paddr(addr);
mem_xact.size(4);
mem_xact.access(MemoryTransaction::READ|MemoryTransaction::ATOMIC);
read_dram_error_corrected(mem_xact);
uint64_t data = mem_xact.getData();
ss_mem->poke32(addr,rd);
return data;
}
/*}}}*/
uint64_t SS_CKMemory::casx( uint64_t addr, uint64_t rd, uint64_t rs2 )/*{{{*/
{
mem_xact.referenceType(MemoryTransaction::DATA);
mem_xact.paddr(addr);
mem_xact.size(8);
mem_xact.access(MemoryTransaction::READ|MemoryTransaction::ATOMIC);
read_dram_error_corrected(mem_xact);
uint64_t data = mem_xact.getData();
if (data == rs2)
{
ss_mem->poke64(addr,rd);
}
return data;
}
/*}}}*/
uint32_t SS_CKMemory::cas( uint64_t addr, uint32_t rd, uint32_t rs2 )/*{{{*/
{
mem_xact.referenceType(MemoryTransaction::DATA);
mem_xact.paddr(addr);
mem_xact.size(4);
mem_xact.access(MemoryTransaction::READ|MemoryTransaction::ATOMIC);
read_dram_error_corrected(mem_xact);
uint32_t data = mem_xact.getData();
if (data == rs2)
{
ss_mem->poke32(addr,rd);
}
return data;
}
/*}}}*/
// read_dram_error_corrected() reads the memory specified in a
// MemoryTransaction, memXact, and applies Chip-Kill error correction
// to the data as needed.
//
// Returns false if memXact specifies no Chip-Kill correction or if the
// access is to the I/O space (where CK doesn't apply).
bool SS_CKMemory::read_dram_error_corrected(MemoryTransaction &memXact)/*{{{*/
{
if (memXact.writeXact()) {
fprintf(stderr, "SS_CKMemory::corrrectDramError() "
"WRITE or READ_WRITE memXact.");
exit(-1);
}
if( memXact.size() < 8 ){
memXact.setData(read_short_corrected_dram_data(memXact.paddr(),
memXact.size()));
} else {
if( memXact.size() % 8 ){
fprintf(stderr, "Read of size %d, is not a multiple of 8 bytes",
memXact.size() );
exit(-1);
}
uint_t size = memXact.size() / 8;
for( uint_t i = 0; i < size; ++i ){
uint64_t data = read_corrected_dram_data(memXact.paddr() + i * 8, 8);
memXact.setData(i, data);
}
}
return true;
}
// read_corrected_dram_data() reads Chip-Kill corrected data from
// paddress. Allowed sizes are 1, 2, 4, and multiples of 8.
uint64_t SS_CKMemory::read_corrected_dram_data(uint64_t paddress,
uint8_t size)/*{{{*/
{
if (size < 8) {
return read_short_corrected_dram_data(paddress, size);
}
if (size % 8) {
fprintf(stderr, "SS_CKMemory::readCorrectedDramData: read of "
"size %d, is not a multiple of 8 bytes", size);
}
uint64_t ckPaddr = paddress & ~(DRAM_LINE_LENGTH - 1);
BL_CKEccFile::ChipKillLine line = read_raw_CK_line(ckPaddr);
if (ecc_exists(ckPaddr)) {
uint64_t storedECC = fetch_ecc(ckPaddr);
uint64_t old_msdw = line.msdw;
uint64_t old_lsdw = line.lsdw;
// if debugging Chip-Kill, inject data errors
if (debug_CK) {
if (random() % 2)
line.msdw ^= ((random() % 16) << (4*(random() % 16)));
else
line.lsdw ^= ((random() % 16) << (4*(random() % 16)));
}
BL_CKSyndrome ckSyndrome(line, storedECC);
// if there is no error for this CK line, remove its ECC value
if (ckSyndrome.noError()) {
dram_ecc_map.erase(ckPaddr);
} else { // try to fix the line
ckSyndrome.correctChipKillLine(line);
}
// if the error weren't fixed, die
if (debug_CK && old_msdw != line.msdw && old_lsdw != line.lsdw) {
fprintf(stderr,"SS_CKMemory::"
"readCorrectedDramData(): "
"Chip-Kill failed");
exit(-1);
}
}
return (paddress & (DRAM_LINE_LENGTH/2)) ? line.lsdw : line.msdw;
}
/*}}}*/
// read_short_corrected_dram_data() reads Chip-Kill corrected data from
// paddress. Allowed sizes are 1, 2, 4.
uint64_t SS_CKMemory::read_short_corrected_dram_data(uint64_t paddress,
uint8_t size)/*{{{*/
{
uint64_t data = read_corrected_dram_data(paddress & ~0x07ULL , 8);
switch( size )
{
case 4:
data = ( data >> ( 32 - (paddress & 0x04ULL) * 8)) & 0x0ffffffff;
break;
case 2:
data = ( data >> ( 48 - (paddress & 0x06ULL) * 8)) & 0x0ffff;
break;
case 1:
data = ( data >> ( 56 - (paddress & 0x07ULL) * 8)) & 0x0ff;
break;
default:
fprintf(stderr, "Read of size %d is not supported. Reads must be "
"1, 2, 4, or 8 bytes.", size );
exit;
}
/*fprintf(stderr, "Read of %d bytes of data from 0x%0.16llx data=%0.16llx\n",
size, paddress, data );*/
return data;
}
/*}}}*/