diff --git a/DRAMSys/simulator/library.pro b/DRAMSys/simulator/library.pro index 8a17d847..c225875c 100644 --- a/DRAMSys/simulator/library.pro +++ b/DRAMSys/simulator/library.pro @@ -114,7 +114,9 @@ SOURCES += \ src/simulation/Setup.cpp \ src/error/ECC/Bit.cpp \ src/error/ECC/ECC.cpp \ - src/error/ECC/Word.cpp + src/error/ECC/Word.cpp \ + src/error/eccbaseclass.cpp \ + src/error/ecchamming.cpp HEADERS += \ src/common/third_party/tinyxml2/tinyxml2.h \ @@ -178,10 +180,11 @@ HEADERS += \ src/simulation/TraceSetup.h \ src/simulation/DRAMSys.h \ src/simulation/Setup.h \ - src/error/controllerECC.h \ src/error/ECC/Bit.h \ src/error/ECC/ECC.h \ - src/error/ECC/Word.h + src/error/ECC/Word.h \ + src/error/eccbaseclass.h \ + src/error/ecchamming.h thermalsim = $$(THERMALSIM) isEmpty(thermalsim) { diff --git a/DRAMSys/simulator/src/error/ECC/Word.cpp b/DRAMSys/simulator/src/error/ECC/Word.cpp index f260d76c..fbf82ef3 100644 --- a/DRAMSys/simulator/src/error/ECC/Word.cpp +++ b/DRAMSys/simulator/src/error/ECC/Word.cpp @@ -1,6 +1,8 @@ #include "Word.h" +#include #include +#include using std::cout; @@ -47,7 +49,7 @@ void CWord::Set(unsigned data) } } -void CWord::Set(unsigned char* data, unsigned lengthInBits) +void CWord::Set(const unsigned char* data, unsigned lengthInBits) { deque::iterator it; if (m_nBitLength < lengthInBits) @@ -143,6 +145,9 @@ void CWord::Print() void CWord::Copy(unsigned char* ptr) { + unsigned len = ceil(m_word.size()/8); + memset(ptr, 0, len); + unsigned pos = 0; for(auto it = m_word.begin(); it != m_word.end(); it++) { diff --git a/DRAMSys/simulator/src/error/ECC/Word.h b/DRAMSys/simulator/src/error/ECC/Word.h index f21432cb..efcdd981 100644 --- a/DRAMSys/simulator/src/error/ECC/Word.h +++ b/DRAMSys/simulator/src/error/ECC/Word.h @@ -21,7 +21,7 @@ public: CBit* GetAt(unsigned nBitPos); void Set(unsigned data); - void Set(unsigned char* data, unsigned lengthInBits); + void Set(const unsigned char* data, unsigned lengthInBits); void Rotate(); bool Insert(unsigned npos, CBit b); diff --git a/DRAMSys/simulator/src/error/controllerECC.h b/DRAMSys/simulator/src/error/controllerECC.h deleted file mode 100644 index 53dc469a..00000000 --- a/DRAMSys/simulator/src/error/controllerECC.h +++ /dev/null @@ -1,239 +0,0 @@ -#ifndef CONTROLLERECC_H -#define CONTROLLERECC_H - -#include - -#include "ECC/ECC.h" - -#include "../common/xmlAddressdecoder.h" -#include "../common/DebugManager.h" - -using namespace std; -using namespace tlm; - -struct ControllerECC: sc_module -{ -private: - map m_mDataPointer; - -public: - tlm_utils::multi_passthrough_target_socket t_socket; - tlm_utils::multi_passthrough_initiator_socket i_socket; - - SC_CTOR(ControllerECC) - : t_socket("t_socket") - , i_socket("i_socket") - { - t_socket.register_nb_transport_fw(this, &ControllerECC::nb_transport_fw); - i_socket.register_nb_transport_bw(this, &ControllerECC::nb_transport_bw); - } - - // Forward interface - virtual tlm::tlm_sync_enum nb_transport_fw( int id, tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_time& delay ) - { - if(trans.get_command() == TLM_WRITE_COMMAND && phase == BEGIN_REQ) - { - // Get data and length - unsigned nDataLength = trans.get_data_length(); - unsigned char* pData = trans.get_data_ptr(); - - // Calculate how many 64 bit blocks are there - unsigned nBlocks = nDataLength>>3; - - // Create new data array for data with ECC - unsigned char* pDataECC = new unsigned char[nBlocks*9]; - memset(pDataECC, 0x0, nBlocks*9*sizeof(unsigned char)); - - // Create ECC data for every block - for(unsigned i = 0; i < nBlocks; i++) - { - // Create all variables needed for calulation - CWord dataword(64); - CWord checkbits(8); - - // Fill in current data block - dataword.Set(&pData[i<<3], 64); - - // Extend data word - ECC::ExtendWord(dataword); - - checkbits = 0; - - // Calculate Checkbits - ECC::CalculateCheckbits(dataword, checkbits); - ECC::InsertCheckbits(dataword, checkbits); - - // Calculate Parity - ECC::CalculateParityBit(dataword, checkbits[7]); - - // Copy old data - memcpy(&pDataECC[i*9], &pData[i<<3], 8); - - // Save hamming code + parity bit in the last byte - checkbits.Copy(&pDataECC[i*9+8]); - } - - // Change transport data length - trans.set_data_length(nBlocks*9); - - // store old data - m_mDataPointer[pDataECC] = trans.get_data_ptr(); - - // Set new data - trans.set_data_ptr(pDataECC); - } - else if(trans.get_command() == TLM_READ_COMMAND && phase == BEGIN_REQ) - { - // 64 -> 72 - - // Get data length - unsigned nDataLength = trans.get_data_length(); - - // Create new pointer - nDataLength += nDataLength>>3; - unsigned char* new_ptr = new unsigned char [nDataLength]; - - // store old data ptr - m_mDataPointer[new_ptr] = trans.get_data_ptr(); - - // Set new data - trans.set_data_ptr(new_ptr); - - // Change transport data length - trans.set_data_length(nDataLength); - } - - return i_socket[id]->nb_transport_fw( trans, phase, delay ); - } - - - // Backward interface - virtual tlm::tlm_sync_enum nb_transport_bw( int id, tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_time& delay ) - { - if(trans.get_command() == TLM_READ_COMMAND && phase == BEGIN_RESP) - { - // Get data and length - unsigned nDataLength = trans.get_data_length(); - unsigned char* pData = trans.get_data_ptr(); - - // Calculate how many 72 bit blocks are there - unsigned nBlocks = nDataLength/9; - - // Verify ECC data for every block - for(unsigned i = 0; i < nBlocks; i++) - { - // Create all variables needed for calulation - CWord dataword(64); - CWord checkbits(8); - - // Fill in current data block - dataword.Set(&pData[i*9], 64); - checkbits.Set(&pData[i*9+8], 8); - - // Extend data word - ECC::ExtendWord(dataword); - - // Insert old checkbits - ECC::InsertCheckbits(dataword, checkbits); - ECC::InsertParityBit(dataword, checkbits[7]); - - checkbits = 0; - - // Calculate Checkbits - ECC::CalculateCheckbits(dataword, checkbits); - - // Calculate Parity - ECC::CalculateParityBit(dataword, checkbits[7]); - - // Translate Checkbits - bool bParity = checkbits[7] == CBit::ONE; - - unsigned char c = 0; - checkbits.Rotate(); - checkbits.Copy(&c); - c &= 0x7F; - - // Parity Error? - if(bParity) - { - // Parity Error - - if(c == 0) - { - // Only Parity Bit broken - continue - cout << "Parity Bit error" << endl; - continue; - } - else - { - // Data or Hamming Code Bit broken - cout << "Single Error Detected" << endl; - continue; - } - } - else - { - // No Parity Error - - if(c == 0) - { - // No error at all - continue - continue; - } - else - { - // Double error detected - cout << "Double Error Detected (Block " << i << ")." << endl; - continue; - } - } - } - // Change transport data length - trans.set_data_length(nBlocks<<3); - - // load data pointer - auto it = m_mDataPointer.find(trans.get_data_ptr()); - assert(it != m_mDataPointer.end()); - - unsigned char* pDataECC = it->second; - - // delete data pointer from map - m_mDataPointer.erase(it); - - // Copy data - memcpy(pDataECC, pData, nBlocks<<3); - - // delete old data - delete[] trans.get_data_ptr(); - - // Set new data - trans.set_data_ptr(pDataECC); - } - else if(trans.get_command() == TLM_WRITE_COMMAND && phase == BEGIN_RESP) - { - // 72 -> 64 - - // delete old data - delete[] trans.get_data_ptr(); - - // Get data length - unsigned nDataLength = trans.get_data_length(); - - // load data pointer - auto it = m_mDataPointer.find(trans.get_data_ptr()); - assert(it != m_mDataPointer.end()); - - trans.set_data_ptr(it->second); - - // delete data pointer from map - m_mDataPointer.erase(it); - - // Change transport data length - trans.set_data_length((nDataLength/9)<<3); - } - - return t_socket[id]->nb_transport_bw( trans, phase, delay ); - } -}; - -#endif // CONTROLLERECC_H diff --git a/DRAMSys/simulator/src/error/eccbaseclass.cpp b/DRAMSys/simulator/src/error/eccbaseclass.cpp new file mode 100644 index 00000000..10deaa02 --- /dev/null +++ b/DRAMSys/simulator/src/error/eccbaseclass.cpp @@ -0,0 +1,83 @@ +#include "eccbaseclass.h" + +tlm::tlm_sync_enum ECCBaseClass::nb_transport_fw( int id, tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_time& delay ) +{ + if(trans.get_command() == TLM_WRITE_COMMAND && phase == BEGIN_REQ) + { + // Allocate memory for encoded data using the size provided by AllocationEncode + unsigned nEncodedDataSize = AllocationSize(trans.get_data_length()); + assert(nEncodedDataSize != 0); + unsigned char* pEncodedData = new unsigned char[nEncodedDataSize]; + + // Save memory pointer and size + m_mDataPointer[pEncodedData].pData = trans.get_data_ptr(); + m_mDataPointer[pEncodedData].nDataSize = trans.get_data_length(); + + // Data Encoding + Encode(trans.get_data_ptr(), trans.get_data_length(), pEncodedData, nEncodedDataSize); + + // Change transport data length and pointer + trans.set_data_length(nEncodedDataSize); + trans.set_data_ptr(pEncodedData); + } + else if(trans.get_command() == TLM_READ_COMMAND && phase == BEGIN_REQ) + { + // Allocate memory for reading data using the size provided by AllocationEncode + unsigned nReadDataSize = AllocationSize(trans.get_data_length()); + assert(nReadDataSize != 0); + unsigned char* pReadData = new unsigned char[nReadDataSize]; + + // Save memory pointer and size + m_mDataPointer[pReadData].pData = trans.get_data_ptr(); + m_mDataPointer[pReadData].nDataSize = trans.get_data_length(); + + // Change transport data length and pointer + trans.set_data_length(nReadDataSize); + trans.set_data_ptr(pReadData); + } + + return i_socket[id]->nb_transport_fw( trans, phase, delay ); +} + + +// Backward interface +tlm::tlm_sync_enum ECCBaseClass::nb_transport_bw( int id, tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_time& delay ) +{ + if(trans.get_command() == TLM_READ_COMMAND && phase == BEGIN_RESP) + { + //Look for the corresponding data pointer for decoding + auto it = m_mDataPointer.find(trans.get_data_ptr()); + assert(it != m_mDataPointer.end()); + + // Data Decoding + Decode(trans.get_data_ptr(), trans.get_data_length(), it->second.pData, it->second.nDataSize); + + // delete data pointer from map + m_mDataPointer.erase(it); + + // Delete data pointer used for encoded data + delete[] trans.get_data_ptr(); + + // Set data pointer and size for decoded data + trans.set_data_ptr(it->second.pData); + trans.set_data_length(it->second.nDataSize); + } + else if(trans.get_command() == TLM_WRITE_COMMAND && phase == BEGIN_RESP) + { + //Look for the corresponding data pointer for decoding + auto it = m_mDataPointer.find(trans.get_data_ptr()); + assert(it != m_mDataPointer.end()); + + // delete data pointer from map + m_mDataPointer.erase(it); + + // Delete data pointer used for encoded data + delete[] trans.get_data_ptr(); + + // Set data pointer and size for decoded data + trans.set_data_ptr(it->second.pData); + trans.set_data_length(it->second.nDataSize); + } + + return t_socket[id]->nb_transport_bw( trans, phase, delay ); +} diff --git a/DRAMSys/simulator/src/error/eccbaseclass.h b/DRAMSys/simulator/src/error/eccbaseclass.h new file mode 100644 index 00000000..1c64f51d --- /dev/null +++ b/DRAMSys/simulator/src/error/eccbaseclass.h @@ -0,0 +1,67 @@ +#ifndef ECCBASECLASS_H +#define ECCBASECLASS_H + +#include +#include +#include +#include + +#include "ECC/ECC.h" + +#include "../common/xmlAddressdecoder.h" +#include "../common/DebugManager.h" + +using namespace std; +using namespace tlm; + +class ECCBaseClass : sc_module +{ +public: + struct DataStruct + { + unsigned char* pData; + unsigned int nDataSize; + }; + +private: + map m_mDataPointer; + +public: + // Function prototype for calculated the size of memory needed for saving the encoded data + // Input nBytes: Number of bytes which have to be encoded + // Return value: Number of bytes which have to be allocated for storing the encoded data + virtual unsigned AllocationSize(unsigned nBytes) = 0; + +protected: + // Function prototype for encoding data. + // Data pointer is provided in pDataIn, length in Bytes provided in nDataIn + // Result should be written in pDataOut, which has a size of nDataOut. + // pDataOut is already allocated with a size given by function AllocationEncode + virtual void Encode(const unsigned char* pDataIn, const unsigned nDataIn, unsigned char* pDataOut, const unsigned nDataOut) = 0; + + + // Function prototype for decoding data. + // Data pointer is provided in pDataIn, length in Bytes provided in nDataIn + // Result should be written in pDataOut, which has a size of nDataOut. + // pDataOut is already allocated with a size given by function AllocationDecode + virtual void Decode(const unsigned char* pDataIn, const unsigned nDataIn, unsigned char* pDataOut, const unsigned nDataOut) = 0; + +public: + tlm_utils::multi_passthrough_target_socket t_socket; + tlm_utils::multi_passthrough_initiator_socket i_socket; + + SC_CTOR(ECCBaseClass) + : t_socket("t_socket") + , i_socket("i_socket") + { + t_socket.register_nb_transport_fw(this, &ECCBaseClass::nb_transport_fw); + i_socket.register_nb_transport_bw(this, &ECCBaseClass::nb_transport_bw); + } + // Forward interface + tlm::tlm_sync_enum nb_transport_fw( int id, tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_time& delay ); + + // Backward interface + tlm::tlm_sync_enum nb_transport_bw( int id, tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_time& delay ); +}; + +#endif // ECCBASECLASS_H diff --git a/DRAMSys/simulator/src/error/ecchamming.cpp b/DRAMSys/simulator/src/error/ecchamming.cpp new file mode 100644 index 00000000..d2427e3b --- /dev/null +++ b/DRAMSys/simulator/src/error/ecchamming.cpp @@ -0,0 +1,160 @@ +#include "ecchamming.h" + +#include "ECC/ECC.h" + +unsigned ECCHamming::AllocationSize(unsigned nBytes) +{ + // For this hamming for 8 bytes one extra byte is needed:l + return nBytes + ceil(nBytes / m_nDatawordSize) * m_nCodewordSize; +} + +void ECCHamming::Encode(const unsigned char* pDataIn, const unsigned nDataIn, unsigned char* pDataOut, const unsigned nDataOut) +{ + // Calculate how many 8 byte blocks are there + unsigned nBlocks = nDataIn/m_nDatawordSize; + + // No partly filled blocks are supported + assert(nDataIn % m_nDatawordSize == 0); + + // Create ECC data for every block + for(unsigned i = 0; i < nBlocks; i++) + { + // Create all variables needed for calulation + CWord dataword(InBits(m_nDatawordSize)); // Size in bits + CWord codeword(InBits(m_nCodewordSize)); // Size in bits + + // Fill in current data block + dataword.Set(&pDataIn[i*m_nDatawordSize], InBits(m_nDatawordSize)); + + // Extend data word. It grows from m_nDatawordSize to m_nDatawordSize + m_nCodewordSize + ECC::ExtendWord(dataword); + + // Initialize the codeword with zeros + codeword = 0; + + // Calculate Checkbits + ECC::CalculateCheckbits(dataword, codeword); + ECC::InsertCheckbits(dataword, codeword); + + // Calculate Parity + ECC::CalculateParityBit(dataword, codeword[7]); + + // Check if there is enough space in the output array (should always be) + assert((i+1)*(m_nDatawordSize + m_nCodewordSize) <= nDataOut); + + // Copy old data + memcpy(&pDataOut[i*(m_nDatawordSize + m_nCodewordSize)], &pDataIn[i*m_nDatawordSize], m_nDatawordSize); + + // Save hamming code + parity bit in the last byte + codeword.Copy(&pDataOut[i*(m_nDatawordSize + m_nCodewordSize)+m_nDatawordSize]); + } + + cout << "Encode:\r\n"; + for(unsigned i = 0; i < nDataIn; i++) + { + cout << setw(2) << setfill('0') << hex << uppercase << (int)pDataIn[i]; + } + cout << endl; + for(unsigned i = 0; i < nDataOut; i++) + { + cout << setw(2) << setfill('0') << hex << uppercase << (int)pDataOut[i]; + } + cout << endl << endl; +} + +void ECCHamming::Decode(const unsigned char* pDataIn, const unsigned nDataIn, unsigned char* pDataOut, const unsigned nDataOut) +{ + // Calculate how many 9 byte blocks are there + unsigned nBlocks = nDataIn/(m_nDatawordSize + m_nCodewordSize); + + // No partly filled blocks are supported + assert(nDataIn % (m_nDatawordSize + m_nCodewordSize) == 0); + + // Verify ECC data for every block + for(unsigned i = 0; i < nBlocks; i++) + { + // Create all variables needed for calulation + CWord dataword(InBits(m_nDatawordSize)); // Size in bits + CWord codeword(InBits(m_nCodewordSize)); // Size in bits + + // Fill in current data block + dataword.Set(&pDataIn[i*(m_nDatawordSize + m_nCodewordSize)], InBits(m_nDatawordSize)); + codeword.Set(&pDataIn[i*(m_nDatawordSize + m_nCodewordSize)+m_nDatawordSize], InBits(m_nCodewordSize)); + + // Extend data word. It grows from m_nDatawordSize to m_nDatawordSize + m_nCodewordSize + ECC::ExtendWord(dataword); + + // Insert old codeword + ECC::InsertCheckbits(dataword, codeword); + ECC::InsertParityBit(dataword, codeword[7]); + + dataword.Print(); + + // Reset codeword + codeword = 0; + + // Calculate Checkbits again + ECC::CalculateCheckbits(dataword, codeword); + + // Calculate Parity again + ECC::CalculateParityBit(dataword, codeword[7]); + + // Translate codeword + bool bParity = codeword[7] == CBit::ONE; + + // calculate syndrome + unsigned char c = 0; + codeword.Rotate(); + codeword.Copy(&c); + c &= 0x7F; + + // Parity Error? + if(bParity) + { + // Parity Error + + if(c == 0) + { + // Only Parity Bit broken - continue + cout << "Parity Bit error" << endl; + } + else + { + // Data or Hamming Code Bit broken + cout << "Single Error Detected" << endl; + } + } + else + { + // No Parity Error + + if(c == 0) + { + // No error at all - continue + } + else + { + // Double error detected + cout << "Double Error Detected (Block " << i << ")." << endl; + } + } + + // Check if there is enough space in the output array (should always be) + assert((i+1)*(m_nDatawordSize) <= nDataOut); + + // Copy data + memcpy(&pDataOut[i*m_nDatawordSize], &pDataIn[i*(m_nDatawordSize + m_nCodewordSize)], m_nDatawordSize); + } + + cout << "Decode:\r\n"; + for(unsigned i = 0; i < nDataIn; i++) + { + cout << setw(2) << setfill('0') << hex << uppercase << (int)pDataIn[i]; + } + cout << endl; + for(unsigned i = 0; i < nDataOut; i++) + { + cout << setw(2) << setfill('0') << hex << uppercase << (int)pDataOut[i]; + } + cout << endl << endl; +} diff --git a/DRAMSys/simulator/src/error/ecchamming.h b/DRAMSys/simulator/src/error/ecchamming.h new file mode 100644 index 00000000..99c548fb --- /dev/null +++ b/DRAMSys/simulator/src/error/ecchamming.h @@ -0,0 +1,41 @@ +#ifndef ECCHAMMIMG_H +#define ECCHAMMIMG_H + +#include "eccbaseclass.h" + + +class ECCHamming : public ECCBaseClass +{ +private: + // Hamming constants for this special implementation + const unsigned m_nDatawordSize = 8; // bytes + const unsigned m_nCodewordSize = 1; // bytes + + inline unsigned InBits(unsigned n){return n<<3;}; // use this if constants are needed in bits + +public: + // Function prototype for calculated the size of memory needed for saving the encoded data + // Input nBytes: Number of bytes which have to be encoded + // Return value: Number of bytes which have to be allocated for storing the encoded data + virtual unsigned AllocationSize(unsigned nBytes); + +protected: + // Function prototype for encoding data. + // Data pointer is provided in pDataIn, length in Bytes provided in nDataIn + // Result should be written in pDataOut, which has a size of nDataOut. + // pDataOut is already allocated with a size given by function AllocationEncode + virtual void Encode(const unsigned char* pDataIn, const unsigned nDataIn, unsigned char* pDataOut, const unsigned nDataOut); + + + // Function prototype for decoding data. + // Data pointer is provided in pDataIn, length in Bytes provided in nDataIn + // Result should be written in pDataOut, which has a size of nDataOut. + // pDataOut is already allocated with a size given by function AllocationDecode + virtual void Decode(const unsigned char* pDataIn, const unsigned nDataIn, unsigned char* pDataOut, const unsigned nDataOut); + +public: + ECCHamming(::sc_core::sc_module_name name) : ECCBaseClass(name) + {}; +}; + +#endif // ECCHAMMIMG_H diff --git a/DRAMSys/simulator/src/simulation/DRAMSys.cpp b/DRAMSys/simulator/src/simulation/DRAMSys.cpp index 16c823a3..f8b3754f 100644 --- a/DRAMSys/simulator/src/simulation/DRAMSys.cpp +++ b/DRAMSys/simulator/src/simulation/DRAMSys.cpp @@ -51,6 +51,7 @@ #include "../common/Utils.h" #include "../simulation/TemperatureController.h" #include "../controller/Controller.h" +#include "../error/ecchamming.h" using namespace std; @@ -192,7 +193,7 @@ void DRAMSys::instantiateModules(const string &traceName, switch (Configuration::getInstance().ECCMode) { case ECCControllerMode::Hamming: - ecc = new ControllerECC("ControllerECC"); + ecc = new ECCHamming("ECCHamming"); break; default: ecc = 0; diff --git a/DRAMSys/simulator/src/simulation/DRAMSys.h b/DRAMSys/simulator/src/simulation/DRAMSys.h index 2b01e65b..63ea9052 100644 --- a/DRAMSys/simulator/src/simulation/DRAMSys.h +++ b/DRAMSys/simulator/src/simulation/DRAMSys.h @@ -51,7 +51,7 @@ #include "../controller/Controller.h" #include "../common/third_party/tinyxml2/tinyxml2.h" #include "../common/tlm2_base_protocol_checker.h" -#include "../error/controllerECC.h" +#include "../error/eccbaseclass.h" class DRAMSys: public sc_module { @@ -80,7 +80,7 @@ private: controllersTlmCheckers; // All transactions pass first through the ECC Controller - ControllerECC *ecc; + ECCBaseClass *ecc; // All transactions pass through the same arbiter Arbiter *arbiter; // Each DRAM unit has a controller