diff --git a/DRAMSys/simulator/library.pro b/DRAMSys/simulator/library.pro index 4cac1673..a0bb357c 100644 --- a/DRAMSys/simulator/library.pro +++ b/DRAMSys/simulator/library.pro @@ -112,7 +112,12 @@ SOURCES += \ src/controller/core/powerdown/PowerDownManagerTimeoutBankwise.cpp \ src/simulation/TraceSetup.cpp \ src/simulation/DRAMSys.cpp \ - src/simulation/Setup.cpp + src/simulation/Setup.cpp \ + src/error/ECC/Bit.cpp \ + src/error/ECC/ECC.cpp \ + src/error/ECC/Word.cpp \ + src/error/eccbaseclass.cpp \ + src/error/ecchamming.cpp HEADERS += \ src/common/third_party/tinyxml2/tinyxml2.h \ @@ -176,7 +181,12 @@ HEADERS += \ src/controller/core/powerdown/PowerDownManagerTimeoutBankwise.h \ src/simulation/TraceSetup.h \ src/simulation/DRAMSys.h \ - src/simulation/Setup.h + src/simulation/Setup.h \ + src/error/ECC/Bit.h \ + src/error/ECC/ECC.h \ + src/error/ECC/Word.h \ + src/error/eccbaseclass.h \ + src/error/ecchamming.h thermalsim = $$(THERMALSIM) isEmpty(thermalsim) { diff --git a/DRAMSys/simulator/resources/configs/mcconfigs/fifo.xml b/DRAMSys/simulator/resources/configs/mcconfigs/fifo.xml index 08135f13..b09a4cfa 100644 --- a/DRAMSys/simulator/resources/configs/mcconfigs/fifo.xml +++ b/DRAMSys/simulator/resources/configs/mcconfigs/fifo.xml @@ -8,13 +8,5 @@ - - - - diff --git a/DRAMSys/simulator/resources/configs/mcconfigs/fifoStrict.xml b/DRAMSys/simulator/resources/configs/mcconfigs/fifoStrict.xml index 5c58a9c5..7ca1a824 100644 --- a/DRAMSys/simulator/resources/configs/mcconfigs/fifoStrict.xml +++ b/DRAMSys/simulator/resources/configs/mcconfigs/fifoStrict.xml @@ -8,13 +8,5 @@ - - - - diff --git a/DRAMSys/simulator/resources/configs/mcconfigs/fifo_ecc.xml b/DRAMSys/simulator/resources/configs/mcconfigs/fifo_ecc.xml new file mode 100644 index 00000000..b09a4cfa --- /dev/null +++ b/DRAMSys/simulator/resources/configs/mcconfigs/fifo_ecc.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/DRAMSys/simulator/resources/configs/mcconfigs/fr_fcfs.xml b/DRAMSys/simulator/resources/configs/mcconfigs/fr_fcfs.xml index fad8b021..0ff319b0 100644 --- a/DRAMSys/simulator/resources/configs/mcconfigs/fr_fcfs.xml +++ b/DRAMSys/simulator/resources/configs/mcconfigs/fr_fcfs.xml @@ -8,14 +8,6 @@ - - - - diff --git a/DRAMSys/simulator/resources/configs/mcconfigs/par_bs.xml b/DRAMSys/simulator/resources/configs/mcconfigs/par_bs.xml index 78a8afd7..63fb4a27 100644 --- a/DRAMSys/simulator/resources/configs/mcconfigs/par_bs.xml +++ b/DRAMSys/simulator/resources/configs/mcconfigs/par_bs.xml @@ -8,13 +8,5 @@ - - - - diff --git a/DRAMSys/simulator/resources/configs/memspecs/MICRON_1Gb_DDR3-1600_8bit_G_less_refresh.xml b/DRAMSys/simulator/resources/configs/memspecs/MICRON_1Gb_DDR3-1600_8bit_G_less_refresh.xml new file mode 100644 index 00000000..7a94a932 --- /dev/null +++ b/DRAMSys/simulator/resources/configs/memspecs/MICRON_1Gb_DDR3-1600_8bit_G_less_refresh.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DRAMSys/simulator/resources/configs/memspecs/wideio_less_refresh.xml b/DRAMSys/simulator/resources/configs/memspecs/wideio_less_refresh.xml new file mode 100644 index 00000000..f8aa3190 --- /dev/null +++ b/DRAMSys/simulator/resources/configs/memspecs/wideio_less_refresh.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DRAMSys/simulator/resources/configs/simulator/ddr3-single-device.xml b/DRAMSys/simulator/resources/configs/simulator/ddr3-single-device.xml index 35fd3dec..354ad0d5 100644 --- a/DRAMSys/simulator/resources/configs/simulator/ddr3-single-device.xml +++ b/DRAMSys/simulator/resources/configs/simulator/ddr3-single-device.xml @@ -11,4 +11,13 @@ + + + + + diff --git a/DRAMSys/simulator/resources/configs/simulator/ddr3.xml b/DRAMSys/simulator/resources/configs/simulator/ddr3.xml index 9e322605..d48f6a8d 100644 --- a/DRAMSys/simulator/resources/configs/simulator/ddr3.xml +++ b/DRAMSys/simulator/resources/configs/simulator/ddr3.xml @@ -11,6 +11,15 @@ + + + + + + + diff --git a/DRAMSys/simulator/resources/configs/simulator/wideio.xml b/DRAMSys/simulator/resources/configs/simulator/wideio.xml index 8ba8f3ba..34c328c3 100644 --- a/DRAMSys/simulator/resources/configs/simulator/wideio.xml +++ b/DRAMSys/simulator/resources/configs/simulator/wideio.xml @@ -10,5 +10,14 @@ + + + + + diff --git a/DRAMSys/simulator/resources/configs/simulator/wideio_ecc.xml b/DRAMSys/simulator/resources/configs/simulator/wideio_ecc.xml new file mode 100644 index 00000000..49967b58 --- /dev/null +++ b/DRAMSys/simulator/resources/configs/simulator/wideio_ecc.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + diff --git a/DRAMSys/simulator/resources/configs/simulator/wideio_thermal.xml b/DRAMSys/simulator/resources/configs/simulator/wideio_thermal.xml index 42dcda72..f3a99d72 100644 --- a/DRAMSys/simulator/resources/configs/simulator/wideio_thermal.xml +++ b/DRAMSys/simulator/resources/configs/simulator/wideio_thermal.xml @@ -10,5 +10,14 @@ + + + + + diff --git a/DRAMSys/simulator/src/error/error.csv b/DRAMSys/simulator/resources/error/wideio.csv similarity index 100% rename from DRAMSys/simulator/src/error/error.csv rename to DRAMSys/simulator/resources/error/wideio.csv diff --git a/DRAMSys/simulator/resources/resources.pri b/DRAMSys/simulator/resources/resources.pri index 914daa88..f240b193 100644 --- a/DRAMSys/simulator/resources/resources.pri +++ b/DRAMSys/simulator/resources/resources.pri @@ -5,6 +5,8 @@ OTHER_FILES += resources/simulations/ddr3-example.xml OTHER_FILES += resources/simulations/ddr3-single-device.xml OTHER_FILES += resources/simulations/wideio-example.xml +OTHER_FILES += resources/simulations/wideio-ecc.xml +OTHER_FILES += resources/simulations/ddr3-ecc.xml OTHER_FILES += resources/simulations/sms-example.xml # Simulator Files @@ -12,6 +14,8 @@ OTHER_FILES += resources/configs/simulator/wideio.xml OTHER_FILES += resources/configs/simulator/ddr3.xml OTHER_FILES += resources/configs/simulator/ddr3-single-device.xml OTHER_FILES += resources/configs/simulator/wideio_thermal.xml +OTHER_FILES += resources/configs/simulator/wideio_ecc.xml +OTHER_FILES += resources/configs/simulator/ddr3_ecc.xml OTHER_FILES += resources/configs/simulator/sms.xml # Scripts @@ -60,6 +64,7 @@ OTHER_FILES += resources/traces/mediabench-adpcmdecode_32.stl OTHER_FILES += resources/traces/ddr3_example.stl OTHER_FILES += resources/traces/ddr3_single_dev_example.stl OTHER_FILES += resources/traces/ddr3_SAMSUNG_M471B5674QH0_DIMM_example.stl +OTHER_FILES += resources/traces/test_ecc.stl OTHER_FILES += resources/traces/sms_t1.stl OTHER_FILES += resources/traces/sms_t2.stl OTHER_FILES += resources/traces/sms_t3.stl @@ -70,6 +75,7 @@ OTHER_FILES += resources/configs/mcconfigs/fifoStrict.xml OTHER_FILES += resources/configs/mcconfigs/fifo.xml OTHER_FILES += resources/configs/mcconfigs/fr_fcfs.xml OTHER_FILES += resources/configs/mcconfigs/par_bs.xml +OTHER_FILES += resources/configs/mcconfigs/fifo_ecc.xml OTHER_FILES += resources/configs/mcconfigs/sms.xml # Memspecs @@ -113,6 +119,8 @@ OTHER_FILES += resources/configs/memspecs/MICRON_4Gb_LPDDR3-1600_32bit_A.xml OTHER_FILES += resources/configs/memspecs/SAMSUNG_K4B1G1646E_1Gb_DDR3-1600_16bit.xml OTHER_FILES += resources/configs/memspecs/SAMSUNG_K4B4G1646Q_4Gb_DDR3-1066_16bit.xml OTHER_FILES += resources/configs/memspecs/wideio.xml +OTHER_FILES += resources/configs/memspecs/wideio_less_refresh.xml +OTHER_FILES += resources/configs/memspecs/MICRON_1Gb_DDR3-1600_8bit_G_less_refresh.xml # Address Mapping Configs OTHER_FILES += resources/configs/amconfigs/am_ddr3.xml @@ -139,3 +147,6 @@ OTHER_FILES += resources/configs/thermalsim/mem.flp OTHER_FILES += resources/configs/thermalsim/powerInfo.xml OTHER_FILES += resources/configs/thermalsim/stack.stk OTHER_FILES += resources/configs/thermalsim/config.xml + +# Error Simulation data +OTHER_FILES += resources/error/wideio.csv diff --git a/DRAMSys/simulator/resources/simulations/ddr3-ecc.xml b/DRAMSys/simulator/resources/simulations/ddr3-ecc.xml new file mode 100644 index 00000000..5760612c --- /dev/null +++ b/DRAMSys/simulator/resources/simulations/ddr3-ecc.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + test_ecc.stl + + diff --git a/DRAMSys/simulator/resources/simulations/wideio-ecc.xml b/DRAMSys/simulator/resources/simulations/wideio-ecc.xml new file mode 100644 index 00000000..ead21319 --- /dev/null +++ b/DRAMSys/simulator/resources/simulations/wideio-ecc.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + test_ecc.stl + + diff --git a/DRAMSys/simulator/src/controller/core/configuration/Configuration.cpp b/DRAMSys/simulator/src/controller/core/configuration/Configuration.cpp index f0fd7f68..6cb0ffb9 100644 --- a/DRAMSys/simulator/src/controller/core/configuration/Configuration.cpp +++ b/DRAMSys/simulator/src/controller/core/configuration/Configuration.cpp @@ -110,6 +110,19 @@ EPowerDownMode string2PDNMode(string s) } } +ECCControllerMode string2ECCControllerMode(string s) +{ + if(s == "Disabled") + return ECCControllerMode::Disabled; + else if(s == "Hamming") + return ECCControllerMode::Hamming; + else + { + SC_REPORT_FATAL("Configuration", ("Unknown ECCControllerMode: " + s).c_str()); + throw; + } +} + enum sc_time_unit string2TimeUnit(string s) { if (s == "s") @@ -209,6 +222,8 @@ void Configuration::setParameter(std::string name, std::string value) } else if(name == "CheckTLM2Protocol") CheckTLM2Protocol = string2bool(value); + else if(name == "ECCControllerMode") + ECCMode = string2ECCControllerMode(value); // Specification for ErrorChipSeed, ErrorCSVFile path and StoreMode else if(name == "ErrorChipSeed") ErrorChipSeed = string2int(value); @@ -317,3 +332,15 @@ unsigned int Configuration::getBytesPerBurst() return bytesPerBurst; } +// Changes the number of bytes depeding on the ECC Controller. This function is needed for modules which get data directly or indirectly from the ECC Controller +unsigned int Configuration::adjustNumBytesAfterECC(unsigned nBytes) +{ + // Manipulate the number of bytes only if there is an ECC Controller selected + if(ECCMode == ECCControllerMode::Disabled) + return nBytes; + else + { + assert(pECC != nullptr); + return pECC->AllocationSize(nBytes); + } +} diff --git a/DRAMSys/simulator/src/controller/core/configuration/Configuration.h b/DRAMSys/simulator/src/controller/core/configuration/Configuration.h index 2f158053..082d7530 100644 --- a/DRAMSys/simulator/src/controller/core/configuration/Configuration.h +++ b/DRAMSys/simulator/src/controller/core/configuration/Configuration.h @@ -45,10 +45,14 @@ #include "thermalSimConfig.h" #include "../../../common/Utils.h" +#include "../../../error/eccbaseclass.h" + enum class StorageMode{NoStorage, Store, ErrorModel}; enum class EPowerDownMode{NoPowerDown, Staggered, TimeoutPDN, TimeoutSREF}; +enum class ECCControllerMode{Disabled, Hamming}; + struct Configuration { static std::string memspecUri; @@ -83,6 +87,9 @@ struct Configuration bool SimulationProgressBar = false; unsigned int NumberOfDevicesOnDIMM = 1; bool CheckTLM2Protocol = false; + ECCControllerMode ECCMode = ECCControllerMode::Disabled; + ECCBaseClass* pECC = nullptr; + bool gem5 = false; unsigned long long int AddressOffset = 0; // MemSpec (from DRAM-Power XML) @@ -102,6 +109,7 @@ struct Configuration std::uint64_t getSimMemSizeInBytes(); unsigned int getDataBusWidth(); unsigned int getBytesPerBurst(); + unsigned int adjustNumBytesAfterECC(unsigned bytes); void setPathToResources(std::string path); std::string getPathToResources(); diff --git a/DRAMSys/simulator/src/error/ECC/Bit.cpp b/DRAMSys/simulator/src/error/ECC/Bit.cpp new file mode 100644 index 00000000..55f28ebf --- /dev/null +++ b/DRAMSys/simulator/src/error/ECC/Bit.cpp @@ -0,0 +1,27 @@ +#include "Bit.h" + +#include + +using std::cout; + +CBit::CBit(VALUE nVal) +{ + m_nValue = nVal; +} + + +CBit::~CBit() +{ +} + +void CBit::Print() +{ + if (m_nValue == ZERO) + { + cout <<"0"; + } + else + { + cout << "1"; + } +} diff --git a/DRAMSys/simulator/src/error/ECC/Bit.h b/DRAMSys/simulator/src/error/ECC/Bit.h new file mode 100644 index 00000000..bfdda476 --- /dev/null +++ b/DRAMSys/simulator/src/error/ECC/Bit.h @@ -0,0 +1,73 @@ +#pragma once +class CBit +{ +public: + enum VALUE + { + ZERO = 0, + ONE = 1 + }; + +protected: + VALUE m_nValue; + +public: + CBit(VALUE nVal = ZERO); + virtual ~CBit(); + + inline void Set() { m_nValue = ONE; }; + inline void Clear() { m_nValue = ZERO; }; + inline unsigned Get() + { + if(m_nValue == ONE) + return 1; + else + return 0; + }; + + void Print(); + + CBit& operator=(unsigned d) + { + if (d == 0 ) + { + m_nValue = ZERO; + } + else + { + m_nValue = ONE; + } + return *this; + } + + friend CBit operator^(CBit l, const CBit& r) + { + if (l.m_nValue == r.m_nValue) + { + return CBit(ZERO); + } + else + { + return CBit(ONE); + } + } + + CBit& operator^=(const CBit& r) + { + if (m_nValue == r.m_nValue) + { + m_nValue = ZERO; + } + else + { + m_nValue = ONE; + } + return *this; + } + + inline bool operator==(const CBit::VALUE& r) + { + return m_nValue == r; + } +}; + diff --git a/DRAMSys/simulator/src/error/ECC/ECC.cpp b/DRAMSys/simulator/src/error/ECC/ECC.cpp new file mode 100644 index 00000000..6cfaffe9 --- /dev/null +++ b/DRAMSys/simulator/src/error/ECC/ECC.cpp @@ -0,0 +1,133 @@ +#include "ECC.h" + +// ************************************************************************************************ +// Function which calculates the number of additional bits needed for a given number of data bits +// to store the hamming code and parity bit for a SECDED implementation +unsigned ECC::GetNumParityBits(unsigned nDataBits) +{ + unsigned nParityBits = 0; + + // Function to calculate the nube of bits: n = 2^k - k - 1 + // ( Source: Hacker's Delight; p. 310; math. function 1 ) + while (nDataBits > ((1 << nParityBits) - nParityBits - 1)) + { + ++nParityBits; + } + + return nParityBits+1; // +1 for the parity bit +} + + +// ************************************************************************************************ +// Function which extends a given data word to the needed length for a SECDED code +void ECC::ExtendWord(CWord & v) +{ + unsigned end = v.GetLength() + ECC::GetNumParityBits(v.GetLength()); + + // Insert x bits for the hamming code at positions where pos = 2^a; a = [0..N] + // In "Hacker's Delight" the smallest index is 1 - But in this beautiful C-Code it's 0 as it + // should be. That's why there is a '-1' in the call of v.Insert. + unsigned i = 1; + while (i < end) + { + v.Insert(i-1, CBit()); + i <<= 1; + } + + // Append one bit for the parity + v.Append(CBit()); +} + +// ************************************************************************************************ +// Function which calculates the Hamming Code bits of an extended Data word. +// Function ExtendWord must be called before calling this function +// The calculated bits are stored in p, so the length of p should be at least +// 'GetNumParityBits(#data bits)-1' +void ECC::CalculateCheckbits(CWord & v, CWord & p) +{ + unsigned i = 1, l = 0; + + // Last bit is the parity bit - don't use this in the algorithm for hamming code + unsigned len = v.GetLength()-1; + + // Following Graph should show you the behaviour of this algorithm + // #Data bits: 11 #Hamming bits: 4 -> SECDED bits: 16 (incl. parity bit) + // Hamming Code Bit: | Bits used -> data(X)/Hamming Code(H) // Bit unused - + // 0 | H-X-X-X-X-X-X-X + // 1 | -HX--XX--XX--XX + // 2 | ---HXXX----XXXX + // 3 | -------HXXXXXXX + // For further information read "Hacker's delight" chapter 15 + // ATTENTION: The order of indices is different from the one in the book, + // but it doesn't matter in which order your data or check bits are. + // But it should be the same for encoding and decoding + while (i < len) + { + for (unsigned j = (i - 1); j < len; j += (i << 1)) + { + for (unsigned k = 0; k < (i); k++) + { + if(j + k >= len) + break; + p[l] ^= v[j + k]; + } + } + l++; + i <<= 1; + } +} + +// ************************************************************************************************ +// Function which inserts the checkbits which were calculated with 'CalculateCheckbits' in the +// extended data word. This is needed to calculate a proper parity of ALL bits to achive a SECDED +// behaviour. +void ECC::InsertCheckbits(CWord& v, CWord p) +{ + unsigned i = 1, j = 0; + while (i <= v.GetLength()-1) + { + v[i - 1] = p[j++]; + i <<= 1; + } +} + + +// ************************************************************************************************ +// Function which extracts the checkbits out of an extended data word. This is needed to check for +// bit error in the data word. +void ECC::ExtractCheckbits(CWord v, CWord & p) +{ + unsigned i = 1, j = 0; + while(i <= v.GetLength()-1) + { + p[j++] = v[i - 1]; + i <<= 1; + } +} + +// ************************************************************************************************ +// Function which calculates the overal parity +// Simply XOR all bits +void ECC::CalculateParityBit(CWord v, CBit & p) +{ + // Paritybit + p = CBit::ZERO; + for (unsigned i = 0; i < v.GetLength(); i++) + { + p ^= v[i]; + } +} + +// ************************************************************************************************ +// Function to insert the parity bit into the extended data word +void ECC::InsertParityBit(CWord& v, CBit p) +{ + v[v.GetLength() - 1] = p; +} + +// ************************************************************************************************ +// Function to extract the parity bit out of an extended data word. +void ECC::ExtractParityBit(CWord v, CBit & p) +{ + p = v[v.GetLength() - 1]; +} diff --git a/DRAMSys/simulator/src/error/ECC/ECC.h b/DRAMSys/simulator/src/error/ECC/ECC.h new file mode 100644 index 00000000..3e9b8238 --- /dev/null +++ b/DRAMSys/simulator/src/error/ECC/ECC.h @@ -0,0 +1,39 @@ +#pragma once + +#include "Word.h" +#include "Bit.h" + +// ************************************************************************************************ +// +// | __/ __/ __| | __| _ _ _ __| |_(_)___ _ _ ___ +// | _| (_| (__ | _| || | ' \/ _| _| / _ \ ' \(_-< +// |___\___\___| |_| \_,_|_||_\__|\__|_\___/_||_/__/ +// +// ------------------------------------------------------------------------------------------------ +// ECC Implementation as described in "Hacker's Delight - second Edition" by Henry S. Warren, Jr. +// ------------------------------------------------------------------------------------------------ +// This namespace gives you some handy functions to get a SEC-DED implementation. +// +// SEC-DED: Single Error Correction - Double Error Detection +// This is the most common error correction code (ECC). +// It consists of two different correction codes: Haming code + parity code. +// +// For further details read chapter 15 of "Hacker's Delight - second Edition" +// ************************************************************************************************ + +namespace ECC +{ + unsigned GetNumParityBits(unsigned nDataBits); + + // Extends the data word that it can be used with hamming code + // Several bits will be included at specific places + void ExtendWord(CWord &v); + + void CalculateCheckbits(CWord &v, CWord & p); + void InsertCheckbits(CWord& v, CWord p); + void ExtractCheckbits(CWord v, CWord& p); + + void CalculateParityBit(CWord v, CBit& p); + void InsertParityBit(CWord& v, CBit p); + void ExtractParityBit(CWord v, CBit& p); +} diff --git a/DRAMSys/simulator/src/error/ECC/ECC_Test.cpp b/DRAMSys/simulator/src/error/ECC/ECC_Test.cpp new file mode 100644 index 00000000..dcbd884e --- /dev/null +++ b/DRAMSys/simulator/src/error/ECC/ECC_Test.cpp @@ -0,0 +1,128 @@ +// ECC_Test.cpp : Definiert den Einstiegspunkt für die Konsolenanwendung. +// + +#include "stdafx.h" +#include +#include "ECC.h" + +int main() +{ + // Random number init + srand(time(NULL)); + + // Erstellen + unsigned size = 4; + CWord p(ECC::GetNumParityBits(size)), v(size); + + // Daten eingeben + for (unsigned a = 0; a < 16; a++) + { + v = a; + v.Rotate(); + + ECC::ExtendWord(v); + printf("%d:\t", a); + + p = 0; + ECC::CalculateCheckbits(v, p); + ECC::InsertCheckbits(v, p); + ECC::CalculateParityBit(v, p[3]); + ECC::InsertParityBit(v, p[3]); + + v.Print(); + + v.Resize(size); + } + + printf("\r\n"); + + for (unsigned x = 0; x < 100; x++) + { + //Get random number + unsigned a = rand() % 16; + + v.Resize(size); + v = a; + v.Rotate(); + + ECC::ExtendWord(v); + + p = 0; + ECC::CalculateCheckbits(v, p); + ECC::InsertCheckbits(v, p); + ECC::CalculateParityBit(v, p[3]); + ECC::InsertParityBit(v, p[3]); + v.Print(); + + // Insert error + unsigned pos = rand() % 8; + v[pos] ^= CBit(CBit::ONE); + + printf("Data: %d, Error at pos %d: ", a, pos + 1); + v[pos].Print(); + printf("\r\n"); + v.Print(); + + p = 0; + ECC::CalculateCheckbits(v, p); + ECC::CalculateParityBit(v, p[3]); + + printf("%d:\t", a); + + p.Print(); + + // Interpreting Data + + unsigned syndrome = 0; + for (unsigned i = 0; i < p.GetLength() - 1; i++) + { + if (p[i] == CBit::ONE) + syndrome += (1 << i); + } + + if (p[3] == CBit::ZERO) + { + // Parity even + + if (syndrome) + { + // Double error + printf("Double error detected.\r\n"); + break; + } + else + { + // No Error + printf("No error detected.\r\n"); + break; + } + } + else + { + // Parity odd + + if (syndrome) + { + // Bit error + printf("Error detected in Bit %d.\r\n", syndrome); + if (syndrome == pos + 1) + continue; + else + break; + } + else + { + // Overall parity Error + printf("Overall parity error detected.\r\n"); + if (pos == 7 || pos == 3 || pos == 1 || pos == 0) + continue; + else + break; + } + } + } + system("pause"); + + return 0; +} + diff --git a/DRAMSys/simulator/src/error/ECC/Word.cpp b/DRAMSys/simulator/src/error/ECC/Word.cpp new file mode 100644 index 00000000..fbf82ef3 --- /dev/null +++ b/DRAMSys/simulator/src/error/ECC/Word.cpp @@ -0,0 +1,157 @@ +#include "Word.h" + +#include +#include +#include + +using std::cout; + +CWord::CWord(unsigned nBitLength) + : m_nBitLength(nBitLength) +{ + m_word.resize(nBitLength); +} + + +CWord::~CWord() +{ +} + +CBit * CWord::GetAt(unsigned nBitPos) +{ + if (nBitPos < m_nBitLength) + { + return &m_word.at(nBitPos); + } + + return nullptr; +} + +void CWord::Set(unsigned data) +{ + deque::iterator it; + if (m_nBitLength < sizeof(data)) + { + it = m_word.begin(); + for (unsigned i = 0; i < m_nBitLength; i++) + { + (*it++) = data & 1; + data >>= 1; + } + } + else + { + for (it = m_word.begin(); it != m_word.end(); it++) + { + (*it) = data & 1; + data >>= 1; + } + } +} + +void CWord::Set(const unsigned char* data, unsigned lengthInBits) +{ + deque::iterator it; + if (m_nBitLength < lengthInBits) + { + it = m_word.begin(); + for (unsigned pos = 0; pos < m_nBitLength; pos++) + { + (*it) = data[pos>>3] & (1 << (7-(pos&7))); + it++; + } + } + else + { + unsigned pos = 0; + for (it = m_word.begin(); it != m_word.end(); it++) + { + (*it) = data[pos>>3] & (1 << (7-(pos&7))); + ++pos; + } + } +} + +void CWord::Rotate() +{ + deque buffer = m_word; + for (unsigned i = 0; i < m_nBitLength; i++) + { + m_word.at(m_nBitLength -i -1) = buffer.at(i); + } +} + +bool CWord::Insert(unsigned npos, CBit b) +{ + if (npos >= m_nBitLength) + return false; + + deque::iterator it = m_word.begin() + npos; + m_word.insert(it, b); + + m_nBitLength++; + + return true; +} + +bool CWord::Delete(unsigned npos) +{ + if (npos >= m_nBitLength) + return false; + + deque::iterator it = m_word.begin() + npos; + m_word.erase(it); + + m_nBitLength++; + + return true; +} + +void CWord::Append(CBit b) +{ + m_word.push_back(b); + + m_nBitLength++; +} + +void CWord::Resize(unsigned nsize) +{ + m_word.resize(nsize); + m_nBitLength = nsize; +} + +bool CWord::PartShiftRight(unsigned nPos, unsigned nShift) +{ + if(nPos >= m_nBitLength) + return false; + + /*for (unsigned i = 0; i < nShift; i++) + { + m_word.insert() + }*/ + + return true; +} + +void CWord::Print() +{ + deque::iterator it; + for (it = m_word.begin(); it != m_word.end(); it++) + { + (*it).Print(); + } + cout << "\r\n"; +} + +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++) + { + ptr[pos>>3] |= (*it).Get() << (7-(pos&7)); + ++pos; + } +} diff --git a/DRAMSys/simulator/src/error/ECC/Word.h b/DRAMSys/simulator/src/error/ECC/Word.h new file mode 100644 index 00000000..efcdd981 --- /dev/null +++ b/DRAMSys/simulator/src/error/ECC/Word.h @@ -0,0 +1,63 @@ +#pragma once + +#include +#include "Bit.h" + +using std::deque; + + +class CWord +{ +protected: + + unsigned m_nBitLength; + deque m_word; + + +public: + CWord(unsigned nBitLength); + virtual ~CWord(); + + CBit* GetAt(unsigned nBitPos); + + void Set(unsigned data); + void Set(const unsigned char* data, unsigned lengthInBits); + void Rotate(); + + bool Insert(unsigned npos, CBit b); + bool Delete(unsigned npos); + + void Copy(unsigned char* ptr); + + void Append(CBit b); + + void Resize(unsigned nsize); + + bool PartShiftRight(unsigned nPos, unsigned nShift); + + inline unsigned GetLength() const { return m_nBitLength; }; + + void Print(); + + CWord& operator=(unsigned d) + { + Set(d); + return *this; + } + + CBit& operator[](unsigned nPos) + { + return m_word.at(nPos); + } + + friend CWord operator >> (CWord l, const unsigned& r) + { + for (unsigned i = 0; i < r; i++) + { + l.m_word.pop_front(); + l.m_word.push_back(CBit(CBit::VALUE::ZERO)); + } + return l; + } +}; + 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..d2d1e466 --- /dev/null +++ b/DRAMSys/simulator/src/error/ecchamming.cpp @@ -0,0 +1,134 @@ +#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]); + } +} + +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]); + + // 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); + } +} 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/error/errormodel.cpp b/DRAMSys/simulator/src/error/errormodel.cpp index 4e397377..e1010f6a 100644 --- a/DRAMSys/simulator/src/error/errormodel.cpp +++ b/DRAMSys/simulator/src/error/errormodel.cpp @@ -49,7 +49,11 @@ void errorModel::init() burstLenght = Configuration::getInstance().memSpec.BurstLength; numberOfColumns = Configuration::getInstance().memSpec.NumberOfColumns; bytesPerColumn = xmlAddressDecoder::getInstance().amount["bytes"]; - numberOfRows = Configuration::getInstance().memSpec.NumberOfRows; + + // Adjust number of bytes per column dynamically to the selected ecc controller + bytesPerColumn = Configuration::getInstance().adjustNumBytesAfterECC(bytesPerColumn); + + numberOfRows = Configuration::getInstance().memSpec.NumberOfRows; numberOfBitErrorEvents = 0; diff --git a/DRAMSys/simulator/src/simulation/DRAMSys.cpp b/DRAMSys/simulator/src/simulation/DRAMSys.cpp index 515c292c..4378b721 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; @@ -58,6 +59,9 @@ DRAMSys::DRAMSys(sc_module_name __attribute__((unused)) name, string simulationToRun, string pathToResources) : tSocket("DRAMSys_tSocket") { + // Initialize ecc pointer + ecc = nullptr; + logo(); // Read Configuration Setup: @@ -185,9 +189,25 @@ void DRAMSys::instantiateModules(const string &traceName, // They need to be ready before creating some modules. setupTlmRecorders(traceName, pathToResources); + // Create new ECC Controller + switch (Configuration::getInstance().ECCMode) + { + case ECCControllerMode::Hamming: + ecc = new ECCHamming("ECCHamming"); + break; + default: + ecc = nullptr; + break; + } + + // Save ECC Controller into the configuration struct to adjust it dynamically + Configuration::getInstance().pECC = ecc; + + // Create arbiter arbiter = new Arbiter("arbiter"); arbiter->setTlmRecorders(tlmRecorders); + // Create DRAM for (size_t i = 0; i < Configuration::getInstance().NumberOfMemChannels; i++) @@ -214,34 +234,46 @@ void DRAMSys::instantiateModules(const string &traceName, void DRAMSys::bindSockets() { - tSocket.bind(arbiter->tSocket); + // If ECC Controller enabled, put it between Trace and arbiter + if(Configuration::getInstance().ECCMode != ECCControllerMode::Disabled) + { + assert(ecc != nullptr); + tSocket.bind(ecc->t_socket); + ecc->i_socket.bind(arbiter->tSocket); + } + else + { + tSocket.bind(arbiter->tSocket); + } - if(Configuration::getInstance().CheckTLM2Protocol) + if(Configuration::getInstance().CheckTLM2Protocol) + { + for (size_t i = 0; + i < Configuration::getInstance().NumberOfMemChannels; + i++) { - for (size_t i = 0; - i < Configuration::getInstance().NumberOfMemChannels; - i++) - { - arbiter->iSocket.bind(controllersTlmCheckers[i]->target_socket); - controllersTlmCheckers[i]->initiator_socket.bind( - controllers[i]->tSocket); - controllers[i]->iSocket.bind(drams[i]->tSocket); - } + arbiter->iSocket.bind(controllersTlmCheckers[i]->target_socket); + controllersTlmCheckers[i]->initiator_socket.bind( + controllers[i]->tSocket); + controllers[i]->iSocket.bind(drams[i]->tSocket); } - else + } + else + { + for (size_t i = 0; + i < Configuration::getInstance().NumberOfMemChannels; + i++) { - for (size_t i = 0; - i < Configuration::getInstance().NumberOfMemChannels; - i++) - { - arbiter->iSocket.bind(controllers[i]->tSocket); - controllers[i]->iSocket.bind(drams[i]->tSocket); - } + arbiter->iSocket.bind(controllers[i]->tSocket); + controllers[i]->iSocket.bind(drams[i]->tSocket); } + } } DRAMSys::~DRAMSys() { + if(ecc) + delete ecc; delete arbiter; diff --git a/DRAMSys/simulator/src/simulation/DRAMSys.h b/DRAMSys/simulator/src/simulation/DRAMSys.h index 3f1aeca9..63ea9052 100644 --- a/DRAMSys/simulator/src/simulation/DRAMSys.h +++ b/DRAMSys/simulator/src/simulation/DRAMSys.h @@ -51,6 +51,7 @@ #include "../controller/Controller.h" #include "../common/third_party/tinyxml2/tinyxml2.h" #include "../common/tlm2_base_protocol_checker.h" +#include "../error/eccbaseclass.h" class DRAMSys: public sc_module { @@ -78,9 +79,10 @@ private: std::vector*> controllersTlmCheckers; + // All transactions pass first through the ECC Controller + ECCBaseClass *ecc; // All transactions pass through the same arbiter Arbiter *arbiter; - // Each DRAM unit has a controller std::vector controllers; diff --git a/DRAMSys/simulator/src/simulation/Dram.h b/DRAMSys/simulator/src/simulation/Dram.h index a5254d97..61d5f941 100644 --- a/DRAMSys/simulator/src/simulation/Dram.h +++ b/DRAMSys/simulator/src/simulation/Dram.h @@ -92,6 +92,8 @@ struct Dram : sc_module SC_CTOR(Dram) : tSocket("socket") { + // Adjust number of bytes per burst dynamically to the selected ecc controller + bytesPerBurst = Configuration::getInstance().adjustNumBytesAfterECC(bytesPerBurst); dramController = NULL; tlmRecorder = NULL; diff --git a/DRAMSys/simulator/src/simulation/StlPlayer.cpp b/DRAMSys/simulator/src/simulation/StlPlayer.cpp index 75817aba..5bf712ed 100644 --- a/DRAMSys/simulator/src/simulation/StlPlayer.cpp +++ b/DRAMSys/simulator/src/simulation/StlPlayer.cpp @@ -123,7 +123,7 @@ void StlPlayer::nextPayload() unsigned long long addr = std::stoull(address.c_str(), 0, 16); // Get the data if necessary. - if (Configuration::getInstance().StoreMode != StorageMode::NoStorage) { + if (Configuration::getInstance().StoreMode != StorageMode::NoStorage && cmd != TLM_READ_COMMAND) { // The input trace file must provide the data to be stored into the memory. iss >> dataStr; if (dataStr.empty()) diff --git a/README.md b/README.md index eb3e5f75..75ce2bc9 100644 --- a/README.md +++ b/README.md @@ -544,6 +544,7 @@ Below, the sub-configurations are listed and explained. + ``` @@ -578,6 +579,9 @@ Below, the sub-configurations are listed and explained. - *CheckTLM2Protocol* (boolean) - "1": enables the TLM 2.0 Protocol Checking - "0": disables the TLM 2.0 Protocol Checking + - *ECCControllerMode* (string) + - "Disabled": No ECC Controller is used + - "Hamming": Enables an ECC Controller with classic SECDED implementation using Hamming Code - **Temperature Simulator Configuration**