EccBaseClass ready to use. ECCHammnigClass created.

This commit is contained in:
Johannes Feldmann
2017-06-20 21:29:03 +02:00
parent d7e843c6e0
commit efbc723bab
10 changed files with 368 additions and 247 deletions

View File

@@ -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) {

View File

@@ -1,6 +1,8 @@
#include "Word.h"
#include <math.h>
#include <iostream>
#include <string.h>
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<CBit>::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++)
{

View File

@@ -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);

View File

@@ -1,239 +0,0 @@
#ifndef CONTROLLERECC_H
#define CONTROLLERECC_H
#include <systemc.h>
#include "ECC/ECC.h"
#include "../common/xmlAddressdecoder.h"
#include "../common/DebugManager.h"
using namespace std;
using namespace tlm;
struct ControllerECC: sc_module
{
private:
map<unsigned char*, unsigned char*> m_mDataPointer;
public:
tlm_utils::multi_passthrough_target_socket<ControllerECC> t_socket;
tlm_utils::multi_passthrough_initiator_socket<ControllerECC> 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

View File

@@ -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 );
}

View File

@@ -0,0 +1,67 @@
#ifndef ECCBASECLASS_H
#define ECCBASECLASS_H
#include <systemc.h>
#include <tlm.h>
#include <tlm_utils/multi_passthrough_initiator_socket.h>
#include <tlm_utils/multi_passthrough_target_socket.h>
#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<unsigned char*, DataStruct> 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<ECCBaseClass> t_socket;
tlm_utils::multi_passthrough_initiator_socket<ECCBaseClass> 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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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