diff --git a/DRAMSys/dramSys/src/error/error.csv b/DRAMSys/dramSys/src/error/error.csv new file mode 100644 index 00000000..22e0d502 --- /dev/null +++ b/DRAMSys/dramSys/src/error/error.csv @@ -0,0 +1,24 @@ +75 64 0 0 0 0 +80 64 0 0 0 0 +85 64 0 0 0 0 +89 64 0 0 0 0 +75 127 0 0 0 0 +80 127 0 0 0 0 +85 127 0 0 0 0 +89 127 2 0.03 2 0.06 +75 145 0 0 0 0 +80 145 0 0 0 0 +85 145 0 0 1 0.03 +89 145 13 0.195 3 0.09 +75 164 0 0 0 0 +80 164 0 0 0 0 +85 164 8 0.12 2 0.06 +89 164 24 0.36 4 0.12 +75 182 0 0 0 0 +80 182 0 0 1 0.03 +85 182 16 0.24 2 0.06 +89 182 41 0.615 8 0.24 +75 200 0 0 0 0 +80 200 5 0.075 3 0.09 +85 200 24 0.36 4 0.12 +89 200 67 1.005 15 0.45 diff --git a/DRAMSys/dramSys/src/error/errormodel.cpp b/DRAMSys/dramSys/src/error/errormodel.cpp new file mode 100644 index 00000000..477adfbb --- /dev/null +++ b/DRAMSys/dramSys/src/error/errormodel.cpp @@ -0,0 +1,741 @@ +/* + * Copyright (c) 2015, University of Kaiserslautern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: + * Matthias Jung + */ + +#include "errormodel.h" +#include "../common/DebugManager.h" +#include +#include +#include + +errorModel::errorModel() +{ + // Get Configuration parameters: + busWidth = Configuration::getInstance().Buswidth; + burstLenght = Configuration::getInstance().memSpec.BurstLength; + numberOfColumns = Configuration::getInstance().memSpec.NumberOfColumns; + bytesPerColumn = xmlAddressDecoder::getInstance().amount["bytes"]; + numberOfRows = Configuration::getInstance().memSpec.NumberOfRows; + numberOfBitErrorEvents = 0; + + // Initialize the lastRow Access array: + lastRowAccess = new sc_time[numberOfRows]; + for(unsigned int i = 0; i < numberOfRows; i++) + { + lastRowAccess[i] = SC_ZERO_TIME; + } + + // The name is set when the context is clear. + name = ""; + + // Parse data input: + parseInputData(); + prepareWeakCells(); + + // Initialize context variables: + myChannel = -1; + myRank = -1; + myBankgroup = -1; + myBank = -1; + + // Test 1: + // If you want to test the function that get the number + // of bit errors for a given temperature and time + // uncomment the following lines: + // + //std::cout << "MAXTemp:" << maxTemperature << std::endl; + //std::cout << "MAXTime:" << maxTime << std::endl; + //getNumberOfFlips(45.0,sc_time(200.0,SC_MS)); + //getNumberOfFlips(45.0,sc_time(190.0,SC_MS)); + //getNumberOfFlips(45.0,sc_time(180.0,SC_MS)); + //getNumberOfFlips(75.0,sc_time(200.0,SC_MS)); + //getNumberOfFlips(75.0,sc_time(190.0,SC_MS)); + //getNumberOfFlips(75.0,sc_time(180.0,SC_MS)); + //getNumberOfFlips(85.0,sc_time(200.0,SC_MS)); + //getNumberOfFlips(85.0,sc_time(190.0,SC_MS)); + //getNumberOfFlips(85.0,sc_time(180.0,SC_MS)); + //getNumberOfFlips(88.0,sc_time(200.0,SC_MS)); + //getNumberOfFlips(88.0,sc_time(190.0,SC_MS)); + //getNumberOfFlips(88.0,sc_time(180.0,SC_MS)); + //getNumberOfFlips(89.0,sc_time(64.0,SC_MS)); + //getNumberOfFlips(89.0,sc_time(64.0,SC_MS)); + //getNumberOfFlips(89.0,sc_time(64.0,SC_MS)); + + // Test 2: + // X X X + // X 1 1 + // X 1 1 + //weakCells[0].bit = 0; + //weakCells[0].col = 0; + //weakCells[0].row = 0; + //weakCells[0].dependent = true; + + setTemperature(89); + markBitFlips(); +} + +errorModel::~errorModel() +{ + // Remove all data from the dataMap: + for (std::map::iterator it = dataMap.begin(); it != dataMap.end(); ++it ) + { + delete it->second; + } + // Delete all elements from the dataMap: + dataMap.clear(); + + // Remove all data from the lastRowAccess + delete [] lastRowAccess; + + // Clean errorMap + errorMap.clear(); + + // Clean list of weak cells: + delete [] weakCells; + + // If an access happened to a bank the numner of error events should be shown: + if(myChannel != -1 && myBank != -1 && myBankgroup != -1 && myRank != -1 ) + { + std::cout << name + << ": Number of Retention Error Events = " << numberOfBitErrorEvents + << std::endl; + } +} + +void errorModel::store(tlm::tlm_generic_payload &trans) +{ + // Check wich bits have flipped during the last access and mark them as flipped: + markBitFlips(); + + // Get the key for the dataMap from the transaction's address: + DecodedAddress key = xmlAddressDecoder::getInstance().decodeAddress(trans.get_address()); + + // Set context: + setContext(key); + + // Check if the provided data length is correct: + assert((bytesPerColumn * burstLenght) == trans.get_data_length()); + + // Handle the DRAM burst, + for (unsigned int i = 0; i < trans.get_data_length(); i+=bytesPerColumn) + { + unsigned char * data; + + // Check if address is not already stored: + if(dataMap.count(key) == 0) + { + // Generate a new data entry + data = new unsigned char[bytesPerColumn]; + } + else // In case the address was stored before: + { + data = dataMap[key]; + } + + // Copy the data from the transaction to the data pointer + memcpy(data, trans.get_data_ptr()+i, bytesPerColumn); + + // Save part of the burst in the dataMap + // TODO: Check if we can have double entries, is key unique? + dataMap.insert(std::pair(key,data)); + + // Reset flipped weak cells in this area, since they are rewritten now + for(unsigned int i = 0; i < maxNumberOfWeakCells; i++) + { + // If the current written column in a row has a week cell: + if(weakCells[i].row == key.row && weakCells[i].col == key.column) + { + // If the bit was marked as flipped due to a retention error + // mark it as unflipped: + if(weakCells[i].flipped == true) + { + weakCells[i].flipped = false; + } + } + } + + // The next burst element is handled, therfore the column address must be increased + key.column++; + + // Check that there is no column overfow: + assert(key.column <= numberOfColumns); + } +} + +void errorModel::load(tlm::tlm_generic_payload &trans) +{ + // Check wich bits have flipped during the last access and mark them as flipped: + markBitFlips(); + + // Get the key for the dataMap from the transaction's address: + DecodedAddress key = xmlAddressDecoder::getInstance().decodeAddress(trans.get_address()); + + // Set context: + setContext(key); + + // Check if the provided data length is correct: + assert((bytesPerColumn * burstLenght) == trans.get_data_length()); + + // Handle the DRAM burst: + for (unsigned int i = 0; i < trans.get_data_length(); i+=bytesPerColumn) + { + // Check if address is not stored: + if(dataMap.count(key) == 0) + { + SC_REPORT_FATAL("errormodel","Reading from an empty memory location"); + } + + // Copy the dataMap to the transaction data pointer + memcpy(trans.get_data_ptr()+i, dataMap[key], bytesPerColumn); + + // The next burst element is handled, therfore the column address must be increased + key.column++; + + // Check that there is no column overfow: + assert(key.column <= numberOfColumns); + } +} + +void errorModel::markBitFlips() +{ + for(unsigned int row = 0; row < Configuration::getInstance().memSpec.NumberOfRows; row++) + { + // Get the time interval between now and the last acivate/refresh + sc_time interval = sc_time_stamp() - lastRowAccess[row]; + + // Obtain the number of bit flips for the current temperature and the time interval: + unsigned int n = getNumberOfFlips(temperature, interval); + + // Check if the current row is in the range of bit flips for this interval + // and temperature, if yes mark it as flipped: + for (unsigned int i=0; i0 transitions are supported) + // DRAMs based on anti cells are not supported yet by this model + if(getBit(key,byte,bitInByte) == 1) + { + // Prepare bit mask: invert mask and AND it later + unsigned char mask = pow(2, bitInByte); + mask = ~mask; + + // Temporal storage for modification: + unsigned char tempByte; + + if(weakCells[i].dependent == false) + { + // Load the affected byte to tempByte + memcpy(&tempByte, dataMap[key]+byte, 1); + + // Flip the bit: + tempByte = (tempByte & mask); + + // Output on the Console: + std::stringstream msg; + msg << "Bit Flipped!" + << " row: " << key.row + << " col: " << key.column + << " bit: " << weakCells[i].bit; + DebugManager::getInstance().printDebugMessage(name, msg.str()); + + numberOfBitErrorEvents++; + + // Copy the modified byte back to the dataMap: + memcpy(dataMap[key]+byte, &tempByte, 1); + } + else // if(weakCells[i].dependent == true) + { + // Get the neighbourhood of the bit and store it in the + // grid variable: + // | 0 1 2 | + // grid = | 3 4 5 | + // | 6 7 8 | + + unsigned int grid[9]; + + grid[0] = getBit(key.row-1,key.column,byte,bitInByte-1); + grid[1] = getBit(key.row-1,key.column,byte,bitInByte ); + grid[2] = getBit(key.row-1,key.column,byte,bitInByte+1); + + grid[3] = getBit(key.row ,key.column,byte,bitInByte-1); + grid[4] = getBit(key.row ,key.column,byte,bitInByte ); + grid[5] = getBit(key.row ,key.column,byte,bitInByte+1); + + grid[6] = getBit(key.row+1,key.column,byte,bitInByte-1); + grid[7] = getBit(key.row+1,key.column,byte,bitInByte ); + grid[8] = getBit(key.row+1,key.column,byte,bitInByte+1); + + unsigned int sum = 0; + for(int s = 0; s < 9; s++) + { + sum += grid[s]; + } + + if(sum <= 4) + { + // Load the affected byte to tempByte + memcpy(&tempByte, dataMap[key]+byte, 1); + + // Flip the bit: + tempByte = (tempByte & mask); + numberOfBitErrorEvents++; + + // Copy the modified byte back to the dataMap: + memcpy(dataMap[key]+byte, &tempByte, 1); + + // Output on the Console: + std::stringstream msg; + msg << "Dependent Bit Flipped!" + << " row: " << key.row + << " col: " << key.column + << " bit: " << weakCells[i].bit + << " sum: " << sum << std::endl + << grid[0] << grid[1] << grid[2] << std::endl + << grid[3] << grid[4] << grid[5] << std::endl + << grid[6] << grid[7] << grid[8]; + DebugManager::getInstance().printDebugMessage(name, msg.str()); + } + else + { + // Output on the Console: + std::stringstream msg; + msg << "Dependent Bit NOT Flipped!" + << " row: " << key.row + << " col: " << key.column + << " bit: " << weakCells[i].bit + << " sum: " << sum << std::endl + << grid[0] << grid[1] << grid[2] << std::endl + << grid[3] << grid[4] << grid[5] << std::endl + << grid[6] << grid[7] << grid[8]; + DebugManager::getInstance().printDebugMessage(name, msg.str()); + } + } + } + } + } + + lastRowAccess[row] = sc_time_stamp(); +} + +// This method is used to get a bit with a key, usually for independent case: +unsigned int errorModel::getBit(DecodedAddress key, unsigned int byteInColumn, unsigned int bitInByte) +{ + // If the data was not writte by the produce yet it is zero: + if(dataMap.count(key) == 0) + { + return 0; + } + else // Return the value of the bit + { + unsigned char tempByte; + + // Copy affected byte to a temporal variable: + memcpy(&tempByte, dataMap[key]+byteInColumn, 1); + unsigned char mask = pow(2, bitInByte); + unsigned int result = (tempByte & mask) >> bitInByte; + std::bitset<8> x(mask); + + std::stringstream msg; + msg << "mask = " << x + << " bitInByte = " << bitInByte + << " tempByte = " << (unsigned int)tempByte + << " result = " << result; + + DebugManager::getInstance().printDebugMessage(name, msg.str()); + + return result; + } +} + +// This method is used to get neighbourhoods, for the dependent case: +unsigned int errorModel::getBit(int row, int column, int byteInColumn, int bitInByte) +{ + // Border-Exception handling: + + // Switch the byte if bit under/overflow: + if(bitInByte < 0) + { + byteInColumn--; + bitInByte = 7; + } + else if(bitInByte >= 8) + { + byteInColumn++; + bitInByte = 0; + } + + // Switch the column if byte under/overflow + if(byteInColumn < 0) + { + column--; + byteInColumn = bytesPerColumn; + } + else if(byteInColumn >= int(byteInColumn)) + { + column++; + byteInColumn = 0; + } + + // If we switch the row we return 0 (culumn under/overflow) + if(column < 0) + { + return 0; + } + else if(column >= int(numberOfColumns)) + { + return 0; + } + + // Row over/underflow return 0 + if(row < 0) + { + return 0; + } + else if(row >= int(numberOfRows)) + { + return 0; + } + + DecodedAddress key; + key.bank = myBank; + key.bankgroup = myBankgroup; + key.channel = myChannel; + key.rank = myRank; + key.column = column; + key.row = row; + + return getBit(key, byteInColumn, bitInByte); +} + +void errorModel::setTemperature(double t) +{ + temperature = t; +} + +void errorModel::parseInputData() +{ + std::string fileName = Configuration::getInstance().ErrorCSVFile; + std::ifstream inputFile(fileName); + + if(inputFile.is_open()) + { + std::string line; + while(std::getline(inputFile,line)) + { + std::istringstream iss(line); + std::string str_temperature; + std::string str_retentionTime; + std::string str_mu_independent; + std::string str_sigma_independent; + std::string str_mu_dependent; + std::string str_sigma_dependent; + + // Parse file: + iss >> str_temperature + >> str_retentionTime + >> str_mu_independent + >> str_sigma_independent + >> str_mu_dependent + >> str_sigma_dependent; + + double temp = std::stod(str_temperature.c_str(), 0); + sc_time retentionTime = sc_time(std::stod(str_retentionTime.c_str(),0),SC_MS); + + unsigned int mu_independent = std::stod(str_mu_independent.c_str(),0); + unsigned int sigma_independent = std::stod(str_sigma_independent.c_str(),0); + unsigned int mu_dependent = std::stod(str_mu_dependent.c_str(),0); + unsigned int sigma_dependent = std::stod(str_sigma_dependent.c_str(),0); + + errors e; + + //calculate normal distribution of # of independent errors + unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); + std::default_random_engine generator(seed); + std::normal_distribution distribution(mu_independent,sigma_independent); + e.independent = ceil(distribution(generator)); + + // calculate normal distribution of # of dependent errors + unsigned seed2 = std::chrono::system_clock::now().time_since_epoch().count(); + std::default_random_engine generator2(seed2); + std::normal_distribution distribution2(mu_dependent,sigma_dependent); + e.dependent = ceil(distribution2(generator2)); + + // Store parsed data to the errorMap: + errorMap[temp][retentionTime] = e; + + std::stringstream msg; + msg << "Temperature = " << temp + << " Time = " << retentionTime + << " independent = " << errorMap[temp][retentionTime].independent + << " dependent = " << errorMap[temp][retentionTime].dependent; + + DebugManager::getInstance().printDebugMessage(name, msg.str()); + } + inputFile.close(); + } + else + { + SC_REPORT_FATAL("errormodel","Cannot open ErrorCSVFile"); + } +} + +void errorModel::prepareWeakCells() +{ + // Get the Maxium number of weak cells by iterating over the errorMap: + maxNumberOfWeakCells = 0; + maxNumberOfDepWeakCells = 0; + for( const auto &i : errorMap ) + { + for( const auto &j : i.second ) + { + // Get number of dependent weak cells: + if( j.second.dependent > maxNumberOfDepWeakCells) + { + maxNumberOfDepWeakCells = j.second.dependent; + } + + // Get the total number of weak cells (independet + dependent): + if( j.second.independent + j.second.dependent > maxNumberOfWeakCells) + { + maxNumberOfWeakCells = j.second.independent + j.second.dependent; + } + } + } + + // Get the highest temperature in the error map: + maxTemperature = 0; + for( const auto &i : errorMap ) + { + if(i.first > maxTemperature) + { + maxTemperature = i.first; + } + } + + // Get the highest time in the error map: + maxTime = SC_ZERO_TIME; + for( const auto &i : errorMap ) + { + for( const auto &j : i.second ) + { + if(j.first > maxTime) + { + maxTime = j.first; + } + } + } + + // Generate weak cells: + + weakCells = new weakCell[maxNumberOfWeakCells]; + + for (unsigned int i=0; i maxTime) + { + SC_REPORT_FATAL("errormodel","time out of range"); + } + else + { + // Find nearest temperature: + double nearestTemperature = 0; + for( const auto &i : errorMap ) + { + if(i.first >= temp) // for worst case reasons we go to the next bin + { + nearestTemperature = i.first; + break; + } + } + + // Find nearest time: + sc_time nearestTime; + for( const auto &i : errorMap[nearestTemperature]) + { + if(i.first >= time) // for worst case reasons we go to the next bin + { + nearestTime = i.first; + break; + } + } + + errors e = errorMap[nearestTemperature][nearestTime]; + + //std::stringstream msg; + //msg << "ACT/REF temp:" << temp + // << " time:" << time + // << " nearestTemp:" << nearestTemperature + // << " nearestTime:" << nearestTime + // << " ind:" << e.independent + // << " dep:" << e.dependent; + + //DebugManager::getInstance().printDebugMessage(name, msg.str()); + + return e.independent + e.dependent; + } + return 0; +} + +void errorModel::setContext(DecodedAddress addr) +{ + // This function is called the first store ore load to get the context in + // which channel, rank or bank the error model is used. + if(myChannel == -1 && myBank == -1 && myBankgroup == -1 && myRank == -1 ) + { + myChannel = addr.channel; + myBank = addr.bank; + myBankgroup = addr.bankgroup; + myRank = addr.rank; + + name = "Channel_" + std::to_string(myChannel) + "_Bank_" + std::to_string(myBank); + } +} diff --git a/DRAMSys/dramSys/src/error/errormodel.h b/DRAMSys/dramSys/src/error/errormodel.h new file mode 100644 index 00000000..9bcfd54c --- /dev/null +++ b/DRAMSys/dramSys/src/error/errormodel.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2015, University of Kaiserslautern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: + * Matthias Jung + */ + +#ifndef ERRORMODEL_H +#define ERRORMODEL_H +#include "../controller/core/configuration/Configuration.h" +#include "../common/xmlAddressdecoder.h" +#include +#include + +class errorModel +{ + public: + errorModel(); + ~errorModel(); + + // Access Methods: + void store(tlm::tlm_generic_payload &trans); + void load(tlm::tlm_generic_payload &trans); + void refresh(unsigned int row); + void activate(unsigned int row); + void setTemperature(double t); + + private: + // Configuration Parameters: + unsigned int busWidth; + unsigned int burstLenght; + unsigned int numberOfColumns; + unsigned int bytesPerColumn; + unsigned int numberOfRows; + + // Name: + std::string name; + + // Online Parameters: + double temperature; + unsigned int numberOfBitErrorEvents; + + // Private Methods: + void parseInputData(); + void prepareWeakCells(); + void markBitFlips(); + unsigned int getNumberOfFlips(double temp, sc_time time); + void setContext(DecodedAddress addr); + unsigned int getBit(DecodedAddress key, unsigned int byte, unsigned int bitInByte); + unsigned int getBit(int row, int column, int byteInColumn, int bitInByte); + + // Input related data structures: + + struct errors + { + double independent; + double dependent; + }; + + // temperature time number of errors + // | | | + std::map > errorMap; + + unsigned int maxNumberOfWeakCells; + unsigned int maxNumberOfDepWeakCells; + double maxTemperature; + sc_time maxTime; + + // Storage of weak cells: + struct weakCell + { + unsigned int row; + unsigned int col; + unsigned int bit; + bool flipped; + bool dependent; + }; + + weakCell * weakCells; + + // To use a map for storing the data a comparing function must be defined + struct DecodedAddressComparer + { + bool operator()( const DecodedAddress& first , const DecodedAddress& second) const + { + sc_dt::uint64 addrFirst = xmlAddressDecoder::getInstance().encodeAddress(first); + sc_dt::uint64 addrSecond = xmlAddressDecoder::getInstance().encodeAddress(second); + return addrFirst < addrSecond; + } + }; + + // The data structure stores complete column accesses + // A DRAM burst will be splitted up in several column accesses + // e.g. BL=4 means that 4 elements will be added to the dataMap! + std::map dataMap; + + // An array to save when the last ACT/REF to a row happened: + sc_time * lastRowAccess; + + // Context Variables (will be written by the first dram access) + int myChannel; + int myRank; + int myBankgroup; + int myBank; +}; + +#endif // ERRORMODEL_H diff --git a/DRAMSys/dramSys/src/simulation/StlDataPlayer.h b/DRAMSys/dramSys/src/simulation/StlDataPlayer.h new file mode 100644 index 00000000..16905881 --- /dev/null +++ b/DRAMSys/dramSys/src/simulation/StlDataPlayer.h @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2015, University of Kaiserslautern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: + * Janik Schlemminger + * Robert Gernhardt + * Matthias Jung + */ + +#ifndef STLDATAPLAYER_H +#define STLDATAPLAYER_H + + +#include "../common/xmlAddressdecoder.h" +#include "TracePlayer.h" + +using namespace std; +using namespace tlm; + +template +struct StlDataPlayer: public TracePlayer +{ +public: + StlDataPlayer(sc_module_name /*name*/, string pathToTrace, unsigned int clkMhz, + TracePlayerListener* listener); + virtual void nextPayload() override + { + string line; + while(line.empty() && file) + { + std::getline(file, line); + } + + if(!file) + { + this->terminate(); + return; + } + + std::istringstream iss(line); + string time, command, address, data; + iss >> time >> command >> address >> data; + + // check if data length in the trace file is correct: + if((data.length()/2) != (bytesPerColumn*burstlength)) + { + SC_REPORT_FATAL("StlDataPlayer", "Data in the trace file has not the right length"); + } + + unsigned long long parsedAdress = std::stoull(address.c_str(), 0, 16); + + gp* payload = this->allocatePayload(); + unsigned char * dataElement = new unsigned char[bytesPerColumn*burstlength]; + + payload->set_address(parsedAdress); + payload->set_response_status(TLM_INCOMPLETE_RESPONSE); + payload->set_dmi_allowed(false); + payload->set_byte_enable_length(0); + payload->set_streaming_width(burstlength); + payload->set_data_length(bytesPerColumn*burstlength); + payload->set_data_ptr(dataElement); + + // set data: + for(int i = 0; i < bytesPerColumn*burstlength ; i++) + { + dataElement[i] = (unsigned char)std::stoi(data.substr(i*2,2).c_str(),0,16); + } + + if (command == "read") + { + payload->set_command(TLM_READ_COMMAND); + } + else if (command == "write") + { + payload->set_command(TLM_WRITE_COMMAND); + + // Parse and set data + string data; + iss >> data; + + if(!data.empty()) + { + //cout << "parsing write data: " << data << std::endl; + + for(int i = 0; i < 16*2; i++) // TODO column / burst breite + { + std::string byteString = "0x"; + byteString.append(data.substr(2*(i+1), 2)); + //cout << byteString << " " << std::stoi(byteString.c_str(), 0, 16) << endl; + dataElement[i] = std::stoi(byteString.c_str(), 0, 16); + } + } + } + else + { + SC_REPORT_FATAL(0, + (string("Corrupted tracefile, command ") + command + string(" unknown")).c_str()); + } + + sc_time sendingTime = std::stoull(time.c_str())*clk; + + if (sendingTime <= sc_time_stamp()) + { + this->payloadEventQueue.notify(*payload, BEGIN_REQ, SC_ZERO_TIME); + } + else + { + this->payloadEventQueue.notify(*payload, BEGIN_REQ, sendingTime - sc_time_stamp()); + } + } + + +private: + ifstream file; + unsigned int burstlength; + unsigned int bytesPerColumn; + sc_time clk; +}; + + +template +StlDataPlayer::StlDataPlayer(sc_module_name /*name*/, string pathToTrace, unsigned int clkMhz, + TracePlayerListener* listener) : + TracePlayer(listener),file(pathToTrace) +{ + if (!file.is_open()) + SC_REPORT_FATAL(0, (string("Could not open trace ") + pathToTrace).c_str()); + + if(clkMhz == 0) + clk = Configuration::getInstance().memSpec.clk; + else + clk = FrequencyToClk(clkMhz); + + this->burstlength = Configuration::getInstance().memSpec.BurstLength; + this->bytesPerColumn = xmlAddressDecoder::getInstance().amount["bytes"]; +} + +#endif // STLDATAPLAYER_H diff --git a/DRAMSys/simulator/resources/configs/memconfigs/fr_fcfs.xml b/DRAMSys/simulator/resources/configs/memconfigs/fr_fcfs.xml index 4285a3cb..bf05420a 100644 --- a/DRAMSys/simulator/resources/configs/memconfigs/fr_fcfs.xml +++ b/DRAMSys/simulator/resources/configs/memconfigs/fr_fcfs.xml @@ -8,8 +8,8 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DRAMSys/tests/error/am_wideio.xml b/DRAMSys/tests/error/am_wideio.xml new file mode 100755 index 00000000..76d14bac --- /dev/null +++ b/DRAMSys/tests/error/am_wideio.xml @@ -0,0 +1,18 @@ + + + + + + + + + + diff --git a/DRAMSys/tests/error/fr_fcfs.xml b/DRAMSys/tests/error/fr_fcfs.xml new file mode 100644 index 00000000..bf05420a --- /dev/null +++ b/DRAMSys/tests/error/fr_fcfs.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + diff --git a/DRAMSys/tests/error/generateErrorTest.pl b/DRAMSys/tests/error/generateErrorTest.pl new file mode 100644 index 00000000..a7a3e73a --- /dev/null +++ b/DRAMSys/tests/error/generateErrorTest.pl @@ -0,0 +1,60 @@ +#!/usr/bin/perl -w +use warnings; +use strict; + +# Assuming this address mapping: +# +# +# +# +# +# +# + +# This is how it should look like later: +# 31: write 0x0 ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + +my $numberOfRows = 8192; +my $numberOfColumnsPerRow = 128; + +my $rowOffset = 0x4000; +my $colOffset = 0x80; + +# Generate Data Pattern: +my $dataPatternByte = "ff"; + +my $dataPattern = ""; +for(my $i = 0; $i < 64; $i++) +{ + $dataPattern .= $dataPatternByte; +} + +my $clkCounter = 0; +my $addr = 0; + +# Generate Trace file (writes): +for(my $row = 0; $row < ($numberOfRows * $rowOffset); $row = $row + $rowOffset) +{ + for(my $col = 0; $col < ($numberOfColumnsPerRow * $colOffset); $col = $col + $colOffset) + { + my $addrHex = sprintf("0x%x", $addr); + print "$clkCounter:\twrite\t$addrHex\t$dataPattern\n"; + $clkCounter++; + $addr += $colOffset; + } +} + +$clkCounter = 350000000; +$addr = 0; + +# Generate Trace file (reads): +for(my $row = 0; $row < ($numberOfRows * $rowOffset); $row = $row + $rowOffset) +{ + for(my $col = 0; $col < ($numberOfColumnsPerRow * $colOffset); $col = $col + $colOffset) + { + my $addrHex = sprintf("0x%x", $addr); + print "$clkCounter:\tread\t$addrHex\t$dataPattern\n"; + $clkCounter++; + $addr += $colOffset; + } +} diff --git a/DRAMSys/tests/error/sim-batch.xml b/DRAMSys/tests/error/sim-batch.xml new file mode 100644 index 00000000..c1a5c478 --- /dev/null +++ b/DRAMSys/tests/error/sim-batch.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + test_error.stl + + + +