diff --git a/DRAMSys/analyzer/businessObjects/phases/phase.h b/DRAMSys/analyzer/businessObjects/phases/phase.h index 62c5ea27..ef8d187a 100644 --- a/DRAMSys/analyzer/businessObjects/phases/phase.h +++ b/DRAMSys/analyzer/businessObjects/phases/phase.h @@ -180,7 +180,7 @@ public: using AUTO_REFRESH::AUTO_REFRESH; protected: virtual QString Name() const override {return "REFA";} - virtual bool isBankwise() const {return false;} + virtual bool isBankwise() const override {return false;} }; class REFB : public AUTO_REFRESH @@ -201,7 +201,7 @@ protected: virtual std::vector getTimesOnCommandBus() const {return {span.Begin()};} virtual QColor getColor(const TraceDrawingProperties &drawingProperties) const override {Q_UNUSED(drawingProperties) return getPhaseColor();} virtual QColor getPhaseColor() const override {return ColorGenerator::getColor(10);} - virtual bool isBankwise() const {return false;} + virtual bool isBankwise() const override {return false;} }; class PDNAB : public Phase @@ -222,7 +222,7 @@ public: using PDNAB::PDNAB; protected: virtual QString Name() const override {return "PDNA";} - virtual bool isBankwise() const {return false;} + virtual bool isBankwise() const override {return false;} }; class PDNPB : public Phase @@ -243,7 +243,7 @@ public: using PDNPB::PDNPB; protected: virtual QString Name() const override {return "PDNP";} - virtual bool isBankwise() const {return false;} + virtual bool isBankwise() const override {return false;} }; class SREFB : public Phase @@ -251,8 +251,8 @@ class SREFB : public Phase public: using Phase::Phase; protected: - virtual QString Name() const {return "SREFB";} - virtual Qt::BrushStyle getBrushStyle() const {return Qt::Dense1Pattern;} + virtual QString Name() const override {return "SREFB";} + virtual Qt::BrushStyle getBrushStyle() const override {return Qt::Dense1Pattern;} virtual QColor getColor(const TraceDrawingProperties &drawingProperties) const override {Q_UNUSED(drawingProperties) return getPhaseColor();} virtual QColor getPhaseColor() const override {return QColor(Qt::black);} virtual Phase::PhaseSymbol getPhaseSymbol() const override {return PhaseSymbol::Rect;} @@ -264,7 +264,7 @@ public: using SREFB::SREFB; protected: virtual QString Name() const override {return "SREF";} - virtual bool isBankwise() const {return false;} + virtual bool isBankwise() const override {return false;} }; diff --git a/DRAMSys/analyzer/businessObjects/timespan.h b/DRAMSys/analyzer/businessObjects/timespan.h index c54f99b0..dcc32839 100644 --- a/DRAMSys/analyzer/businessObjects/timespan.h +++ b/DRAMSys/analyzer/businessObjects/timespan.h @@ -38,6 +38,7 @@ #ifndef TIMESPAN_H #define TIMESPAN_H #include +#include #include "tracetime.h" class Timespan @@ -47,7 +48,7 @@ class Timespan public: Timespan(traceTime begin = 0, traceTime end = 0) : begin(begin), end(end){} - traceTime timeCovered() const{return abs(End()-Begin());} + traceTime timeCovered() const{return std::abs(End()-Begin());} traceTime Begin() const{return begin;} void setBegin(traceTime time){begin = time;} traceTime End() const{return end;} diff --git a/DRAMSys/simulator/library.pro b/DRAMSys/simulator/library.pro index 5e9f63a4..a0bb357c 100644 --- a/DRAMSys/simulator/library.pro +++ b/DRAMSys/simulator/library.pro @@ -81,6 +81,7 @@ SOURCES += \ src/controller/scheduler/PARBS.cpp \ src/controller/scheduler/Fr_Fcfs.cpp \ src/controller/scheduler/Fifo.cpp \ + src/controller/scheduler/SMS.cpp \ src/controller/core/refresh/RefreshManagerBankwise.cpp \ src/controller/core/refresh/RefreshManager.cpp \ src/controller/core/scheduling/checker/WriteChecker.cpp \ @@ -111,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 \ @@ -130,6 +136,7 @@ HEADERS += \ src/controller/scheduler/PARBS.h \ src/controller/scheduler/Fr_Fcfs.h \ src/controller/scheduler/Fifo.h \ + src/controller/scheduler/SMS.h \ src/controller/Controller.h \ src/controller/core/refresh/RefreshManagerBankwise.h \ src/controller/core/refresh/RefreshManager.h \ @@ -174,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/mcconfigs/sms.xml b/DRAMSys/simulator/resources/configs/mcconfigs/sms.xml new file mode 100644 index 00000000..088a9f66 --- /dev/null +++ b/DRAMSys/simulator/resources/configs/mcconfigs/sms.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file 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/sms.xml b/DRAMSys/simulator/resources/configs/simulator/sms.xml new file mode 100644 index 00000000..deec1b3b --- /dev/null +++ b/DRAMSys/simulator/resources/configs/simulator/sms.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + 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 fc1d85c7..f240b193 100644 --- a/DRAMSys/simulator/resources/resources.pri +++ b/DRAMSys/simulator/resources/resources.pri @@ -5,14 +5,18 @@ 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 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 OTHER_FILES += resources/scripts/address_scrambler.pl @@ -60,12 +64,19 @@ 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 +OTHER_FILES += resources/traces/sms_t4.stl # Memory Controller Configs 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 OTHER_FILES += resources/configs/memspecs/memspec.dtd @@ -108,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 @@ -134,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/sms-example.xml b/DRAMSys/simulator/resources/simulations/sms-example.xml new file mode 100644 index 00000000..d40e0e8c --- /dev/null +++ b/DRAMSys/simulator/resources/simulations/sms-example.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + ddr3_example.stl + sms_t1.stl + sms_t2.stl + sms_t3.stl + sms_t4.stl + stream.stl + random.stl + chstone-adpcm_32.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/common/tlm2_base_protocol_checker.h b/DRAMSys/simulator/src/common/tlm2_base_protocol_checker.h index eb0833a1..99b5ce10 100755 --- a/DRAMSys/simulator/src/common/tlm2_base_protocol_checker.h +++ b/DRAMSys/simulator/src/common/tlm2_base_protocol_checker.h @@ -343,7 +343,7 @@ void tlm2_base_protocol_checker:: BOILERPLATE b_transport_pre_checks( - tlm::tlm_generic_payload& trans, sc_core::sc_time& delay) + tlm::tlm_generic_payload& trans, sc_core::sc_time& /*delay*/) { ++ m_map[&trans].b_call; @@ -372,7 +372,7 @@ b_transport_pre_checks( BOILERPLATE b_transport_post_checks( - tlm::tlm_generic_payload& trans, sc_core::sc_time& delay) + tlm::tlm_generic_payload& trans, sc_core::sc_time& /*delay*/) { check_response_path(trans, "b_transport"); check_trans_not_modified(trans, "b_transport"); @@ -914,7 +914,7 @@ get_direct_mem_ptr_pre_checks( BOILERPLATE -get_direct_mem_ptr_post_checks( tlm::tlm_generic_payload& trans, tlm::tlm_dmi& dmi_data ) +get_direct_mem_ptr_post_checks( tlm::tlm_generic_payload& trans, tlm::tlm_dmi& /*dmi_data*/ ) { tlm::tlm_generic_payload* init = m_map[&trans].gp; diff --git a/DRAMSys/simulator/src/controller/Controller.cpp b/DRAMSys/simulator/src/controller/Controller.cpp index eee71da6..bf68d7d4 100644 --- a/DRAMSys/simulator/src/controller/Controller.cpp +++ b/DRAMSys/simulator/src/controller/Controller.cpp @@ -53,6 +53,10 @@ void Controller::buildScheduler() { scheduler = new FR_FCFS(*controllerCore); } + else if (selectedScheduler == "SMS") + { + scheduler = new SMS("SMS", *controllerCore, Configuration::getInstance().SJFProbability); + } //else if (selectedScheduler == "PAR_BS") //{ // scheduler = new PAR_BS(*controllerCore,Configuration::getInstance().RefreshAwareScheduling, @@ -296,6 +300,11 @@ void Controller::frontendPEQCallback(tlm_generic_payload &payload, const tlm_pha scheduler->schedule(&payload); scheduleNextFromScheduler(DramExtension::getExtension(payload).getBank()); } + else if (phase == PendingRequest) + { + // Schedule a pending request. + scheduleNextFromScheduler(DramExtension::getExtension(payload).getBank()); + } else if (phase == END_RESP) { if (backpressure != NULL) @@ -361,6 +370,7 @@ void Controller::scheduleNextFromScheduler(Bank bank) return; } + bool rescheduled = true; pair nextRequest = scheduler->getNextRequest(bank); if(nextRequest.second != NULL) { @@ -368,7 +378,17 @@ void Controller::scheduleNextFromScheduler(Bank bank) controllerCore->scheduleRequest(nextRequest.first, *nextRequest.second); printDebugMessage("\t-> Next payload was scheduled by core [" + commandToString(nextRequest.first) + "]"); } + else + { + gp* pendingRequest = scheduler->getPendingRequest(bank); + if (pendingRequest != NULL) + { + rescheduled = true; + frontendPEQ.notify(*(pendingRequest), PendingRequest, Configuration::getInstance().memSpec.clk); + } + } + queue blocked; while (!blockedRequests.empty()) { bank = blockedRequests.front(); blockedRequests.pop(); @@ -379,7 +399,23 @@ void Controller::scheduleNextFromScheduler(Bank bank) controllerCore->scheduleRequest(nextRequest.first, *nextRequest.second); printDebugMessage("\t-> Next payload was scheduled by core [" + commandToString(nextRequest.first) + "] (unblocked)"); } + else + { + gp* pendingRequest = scheduler->getPendingRequest(bank); + if(pendingRequest != NULL) + { + //Pending request + if(!rescheduled) + { + rescheduled = true; + frontendPEQ.notify(*(pendingRequest), PendingRequest, Configuration::getInstance().memSpec.clk); + } + else + blocked.push(bank); + } + } } + blockedRequests = blocked; } void Controller::sendToFrontend(tlm_generic_payload &payload, const tlm_phase &phase, const sc_time &delay) diff --git a/DRAMSys/simulator/src/controller/Controller.h b/DRAMSys/simulator/src/controller/Controller.h index 74695fe3..b5f67ff7 100644 --- a/DRAMSys/simulator/src/controller/Controller.h +++ b/DRAMSys/simulator/src/controller/Controller.h @@ -67,11 +67,14 @@ #include "scheduler/Fifo.h" #include "scheduler/FifoStrict.h" #include "scheduler/Fr_Fcfs.h" +#include "scheduler/SMS.h" #include "scheduler/IScheduler.h" using namespace std; using namespace tlm; +DECLARE_EXTENDED_PHASE(PendingRequest); + struct Controller: public sc_module, public IController { public: @@ -85,7 +88,7 @@ public: tSocket.register_transport_dbg(this, &Controller::transport_dbg); } - ~Controller() + virtual ~Controller() { delete controllerCore; delete scheduler; @@ -109,7 +112,7 @@ private: void buildScheduler(); void payloadEntersSystem(tlm_generic_payload& payload); void payloadLeavesSystem(tlm_generic_payload& payload); - void scheduleNextFromScheduler(Bank bank); + void scheduleNextFromScheduler(Bank bank) override; // --- FRONTEND ------ tlm_sync_enum nb_transport_fw(tlm_generic_payload& payload, tlm_phase& phase, sc_time& fwDelay); diff --git a/DRAMSys/simulator/src/controller/core/ControllerCore.h b/DRAMSys/simulator/src/controller/core/ControllerCore.h index 7f32e805..821c2944 100644 --- a/DRAMSys/simulator/src/controller/core/ControllerCore.h +++ b/DRAMSys/simulator/src/controller/core/ControllerCore.h @@ -55,7 +55,7 @@ class ControllerCore : public sc_module { public: ControllerCore(sc_module_name /*name*/, IController& controller, std::map& numberOfPayloads); - virtual ~ControllerCore() ; + virtual ~ControllerCore(); void scheduleRequest(Command command, tlm::tlm_generic_payload& payload); void triggerRefresh(tlm::tlm_generic_payload& payload); diff --git a/DRAMSys/simulator/src/controller/core/configuration/Configuration.cpp b/DRAMSys/simulator/src/controller/core/configuration/Configuration.cpp index ded14c17..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") @@ -140,6 +153,14 @@ void Configuration::setParameter(std::string name, std::string value) MaxNrOfTransactions = string2int(value); else if(name == "Scheduler") Scheduler = value; + else if(name == "SJFProbability") + if (string2int(value) > 100 || string2int(value) < 0) { + SC_REPORT_FATAL("Configuration", ("Invalid value for parameter " + name + ". This parameter must be between 0 and 100.").c_str()); + } else { + SJFProbability = string2int(value); + } + else if (name == "RequestBufferSize") + RequestBufferSize = string2int(value); else if(name == "Capsize") Capsize = string2int(value); else if(name == "PowerDownTimeout") @@ -201,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); @@ -309,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 8695b133..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; @@ -62,6 +66,8 @@ struct Configuration bool OpenPagePolicy = true; unsigned int MaxNrOfTransactions = 8; std::string Scheduler; + unsigned int SJFProbability; + unsigned int RequestBufferSize; unsigned int Capsize = 5; sc_time getPowerDownTimeout(){return powerDownTimeoutInClk*memSpec.clk;} EPowerDownMode PowerDownMode = EPowerDownMode::Staggered; @@ -81,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) @@ -100,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/controller/scheduler/Fifo.cpp b/DRAMSys/simulator/src/controller/scheduler/Fifo.cpp index beb57612..7d7a90e1 100644 --- a/DRAMSys/simulator/src/controller/scheduler/Fifo.cpp +++ b/DRAMSys/simulator/src/controller/scheduler/Fifo.cpp @@ -60,4 +60,9 @@ pair Fifo::getNextRequest(Bank bank) return pair(Command::NOP, NULL); } +gp* Fifo::getPendingRequest(Bank bank) +{ + return NULL; +} + diff --git a/DRAMSys/simulator/src/controller/scheduler/Fifo.h b/DRAMSys/simulator/src/controller/scheduler/Fifo.h index 0576bb32..1b060b12 100644 --- a/DRAMSys/simulator/src/controller/scheduler/Fifo.h +++ b/DRAMSys/simulator/src/controller/scheduler/Fifo.h @@ -52,6 +52,7 @@ public: void schedule(gp* payload) override; std::pair getNextRequest(Bank bank) override; + virtual gp* getPendingRequest(Bank bank) override; private: std::map> buffer; diff --git a/DRAMSys/simulator/src/controller/scheduler/FifoStrict.cpp b/DRAMSys/simulator/src/controller/scheduler/FifoStrict.cpp index f9881fee..6e8bd292 100644 --- a/DRAMSys/simulator/src/controller/scheduler/FifoStrict.cpp +++ b/DRAMSys/simulator/src/controller/scheduler/FifoStrict.cpp @@ -128,3 +128,7 @@ std::pair FifoStrict::getNextRequest(Bank b return pair(Command::NOP, NULL); } +gp* FifoStrict::getPendingRequest(Bank bank) +{ + return NULL; +} diff --git a/DRAMSys/simulator/src/controller/scheduler/FifoStrict.h b/DRAMSys/simulator/src/controller/scheduler/FifoStrict.h index 1cc9ece0..855f7ff3 100644 --- a/DRAMSys/simulator/src/controller/scheduler/FifoStrict.h +++ b/DRAMSys/simulator/src/controller/scheduler/FifoStrict.h @@ -56,6 +56,7 @@ public: void schedule(gp* payload) override; std::pair getNextRequest(Bank bank) override; + virtual gp* getPendingRequest(Bank bank) override; private: std::deque> buffer; diff --git a/DRAMSys/simulator/src/controller/scheduler/Fr_Fcfs.cpp b/DRAMSys/simulator/src/controller/scheduler/Fr_Fcfs.cpp index 30750c7f..5b022ca6 100644 --- a/DRAMSys/simulator/src/controller/scheduler/Fr_Fcfs.cpp +++ b/DRAMSys/simulator/src/controller/scheduler/Fr_Fcfs.cpp @@ -121,3 +121,8 @@ deque::iterator FR_FCFS::FindRowHit(Bank bank) return queue.end(); } + +gp* FR_FCFS::getPendingRequest(Bank bank) +{ + return NULL; +} diff --git a/DRAMSys/simulator/src/controller/scheduler/Fr_Fcfs.h b/DRAMSys/simulator/src/controller/scheduler/Fr_Fcfs.h index 187b81ab..9347c21f 100644 --- a/DRAMSys/simulator/src/controller/scheduler/Fr_Fcfs.h +++ b/DRAMSys/simulator/src/controller/scheduler/Fr_Fcfs.h @@ -53,6 +53,7 @@ public: void schedule(gp* payload) override; std::pair getNextRequest(Bank bank) override; + virtual gp* getPendingRequest(Bank bank) override; private: std::map> buffer; diff --git a/DRAMSys/simulator/src/controller/scheduler/IScheduler.h b/DRAMSys/simulator/src/controller/scheduler/IScheduler.h index a951d015..efeebdc4 100644 --- a/DRAMSys/simulator/src/controller/scheduler/IScheduler.h +++ b/DRAMSys/simulator/src/controller/scheduler/IScheduler.h @@ -54,6 +54,7 @@ public: virtual void schedule(gp* payload) = 0; virtual std::pair getNextRequest(Bank bank) = 0; + virtual gp* getPendingRequest(Bank bank) = 0; static std::string sendername; protected: diff --git a/DRAMSys/simulator/src/controller/scheduler/SMS.cpp b/DRAMSys/simulator/src/controller/scheduler/SMS.cpp new file mode 100644 index 00000000..64882dc3 --- /dev/null +++ b/DRAMSys/simulator/src/controller/scheduler/SMS.cpp @@ -0,0 +1,357 @@ +#include "SMS.h" +#include + +using namespace std; + +void SMS::schedule(gp *payload) +{ + Thread thread = DramExtension::getExtension(payload).getThread(); + bool wasEmpty = isRequestBuffersEmpty(); + + requestBuffers[thread].emplace_back(payload); + + if (inFlightMemRequestCounter.find(thread) == inFlightMemRequestCounter.end()) { + inFlightMemRequestCounter[thread] = 0; + cacheMisses[thread] = 0; + } + inFlightMemRequestCounter[thread]++; + cacheMisses[thread]++; + + if (wasEmpty) { + newRequest.notify(SC_ZERO_TIME); + } +} + +std::pair SMS::getNextRequest(Bank bank) +{ + if (bankBuffers[bank].empty()) + { + debugManager.printDebugMessage(name(), + "Get next request on bank " + to_string(bank.ID()) + " : EMPTY buffer"); + return pair(Command::NOP, NULL); + } + else + { + gp* payload = bankBuffers[bank].front(); + Command command = IScheduler::getNextCommand(*payload); + if (command == Command::Read || command == Command::ReadA || command == Command::Write + || command == Command::WriteA) + { + inFlightMemRequestCounter[DramExtension::getExtension(payload).getThread()]--; + bankBuffers[bank].pop_front(); + } + + debugManager.printDebugMessage(name(), "Get next request on bank " + to_string(bank.ID())); + return pair(command, payload); + } +} + +void SMS::batchScheduler() +{ + sc_time memClk = Configuration::getInstance().memSpec.clk; + std::default_random_engine generator; + std::bernoulli_distribution distribution((double) SJFprobability / 100.0); + + while (true) + { + updateMPKCs(memClk); + if (isRequestBuffersEmpty()) { + wait(newRequest); + } else { + multiBatchFormation(memClk); + if (existReadyBatches()) { + if (!isSystemLightlyLoaded() && (existLowIntensityThread() || distribution(generator))) { + if (pickSJF()) { + drain(memClk, (*lastSelectedThread).second.front()); + (*lastSelectedThread).second.pop_front(); + } + } else { + if (pickRR()) { + drain(memClk, (*lastSelectedThread).second.front()); + (*lastSelectedThread).second.pop_front(); + } + } + } else { + wait(memClk); + } + } + } +} + +/** + * Pick a Thread according to Shortest-Job Policy + * Save the picked one into lastSelectedThread + * @return true if it can, otherwise false + */ +bool SMS::pickSJF() +{ + // find threads with ready batches + std::vector threadsWithReadyBatches; + for (auto& each : readyBatchIters) + { + if (!each.second.empty()) + { + // marked as thread with non-empty request buffer + threadsWithReadyBatches.push_back(each.first); + } + } + + if (!threadsWithReadyBatches.empty()) + { + // pick shortest-job thread among threads with non-empty request buffer + Thread minThread = threadsWithReadyBatches.front(); + for (auto& thread : threadsWithReadyBatches) + { + if (inFlightMemRequestCounter[thread] < inFlightMemRequestCounter[minThread]) + { + minThread = thread; + } + } + + // save selected thread + lastSelectedThread = readyBatchIters.find(minThread); + debugManager.printDebugMessage(name(), + "[SJF] Select ready batch of thread " + to_string(minThread.ID())); + return true; + } + else + { + return false; + } +} + +/** + * Drain the picked request buffer into bank buffers + * by move request one-by-one from start of the request buffer till last parameter + * @param memClk + * @param last + */ +void SMS::drain(sc_time memClk, std::deque::iterator last) +{ + Thread selectedThread = (*lastSelectedThread).first; + unsigned int batchSize = std::distance(requestBuffers[selectedThread].begin(), last) + 1; + for (unsigned int i = 1; i <= batchSize; i++) + { + Bank bank = DramExtension::getExtension(requestBuffers[selectedThread].front()).getBank(); + // if(bankBuffers[bank].size() == Configuration::getInstance().BankBufferSize) + // { + // wait(bankBufferIsNotFull); + // } + wait(memClk); + bankBuffers[bank].emplace_back(requestBuffers[selectedThread].front()); + requestBuffers[selectedThread].pop_front(); + + debugManager.printDebugMessage(name(), + "[SJF] Drain request in the ready batch of thread " + + to_string((*lastSelectedThread).first.ID()) + " to bankbuffer " + + to_string(bank.ID())); + } +} + +/** + * Pick a Thread according to Round-Robin Policy + * Save the picked one into lastSelectedThread + * @return true if it can pick one, otherwise false + */ +bool SMS::pickRR() +{ + std::map>::iterator nextSelectedThread; + if (lastSelectedThread == readyBatchIters.end()) + { + lastSelectedThread = readyBatchIters.begin(); + nextSelectedThread = lastSelectedThread; + } + else + { + nextSelectedThread = lastSelectedThread; + nextSelectedThread++; + if (nextSelectedThread == readyBatchIters.end()) + nextSelectedThread = readyBatchIters.begin(); + } + + std::map>::iterator savedOriginalNextSelectedThread = nextSelectedThread; + + while ((*nextSelectedThread).second.empty()) + { + nextSelectedThread++; + if (nextSelectedThread == readyBatchIters.end()) + { + nextSelectedThread = readyBatchIters.begin(); + } + + if (nextSelectedThread == savedOriginalNextSelectedThread) + { + // the next thread is the original thread, that mean req buffer are totally empty + // non-existed ready batch to be picked up & drained + return false; + } + } + // save last selected thread + lastSelectedThread = nextSelectedThread; + debugManager.printDebugMessage(name(), + "[RR] Select ready batch of thread " + to_string((*nextSelectedThread).first.ID())); + return true; +} + +bool SMS::isSystemLightlyLoaded() { + unsigned int totalRequest = 0; + for (auto& bankBuffer : bankBuffers) { + totalRequest += bankBuffer.second.size(); + } + return (totalRequest <= LOW_SYSTEM_LOAD); +} + +bool SMS::existLowIntensityThread() { + for (auto& mpkcPerThread : MPKCs) { + if (mpkcPerThread.second < LOW_MPKC) { + return true; + } + } + return false; +} + +bool SMS::isThresholdAgeExceeded(Thread thread, sc_time memClk, std::deque::iterator begin, std::deque::iterator end) { + // find the oldest request in the thread's batch + sc_time oldestGenerationTime = sc_time_stamp(); + for (auto reqIter = begin; reqIter != end; reqIter++) { + sc_time reqGenerationTime = GenerationExtension::getExtension(*reqIter).TimeOfGeneration(); + if (reqGenerationTime < oldestGenerationTime) { + oldestGenerationTime = reqGenerationTime; + } + } + + // check threshold age according to the thread's MPKC + sc_time oldestRequestAge = sc_time_stamp() - oldestGenerationTime; + if ((MPKCs[thread] <= MEDIUM_MPKC) && (oldestRequestAge > (MEDIUM_THRESHOLD_AGE * memClk))) { + return true; + } else if ((MPKCs[thread] > MEDIUM_MPKC) && (oldestRequestAge > (HIGH_THRESHOLD_AGE * memClk))) { + return true; + } else { + return false; + } +} + +void SMS::updateMPKCs(sc_time memClk) { + if (sc_time_stamp() % (MPKC_RESET_CYCLE * memClk) <= memClk) { + // reset for every 10k clk cycles + for (auto& cacheMiss : cacheMisses) { + MPKCs[cacheMiss.first] = 0; + } + debugManager.printDebugMessage(name(), "Reset MKKCs"); + } else { + // update MPKC for every thread + for (auto& cacheMiss : cacheMisses) { + MPKCs[cacheMiss.first] = (cacheMiss.second * 1000.0 * memClk) / (sc_time_stamp()); + } + debugManager.printDebugMessage(name(), "Update MPKCs"); + } +} + +bool SMS::isExceededReqBufferSize(Thread thread) { + return requestBuffers[thread].size() == Configuration::getInstance().RequestBufferSize; +} + +bool SMS::isRequestBuffersEmpty() { + for (auto& requestBuffer : requestBuffers) { + if (!requestBuffer.second.empty()) { + return false; + } + } + return true; +} + +bool SMS::existReadyBatches() { + for (auto& each : readyBatchIters) { + if (!each.second.empty()) { + return true; + } + } + return false; +} + +/** + * Form batch from begin iterator parameter of a request buffer + * If this batch is deemed ready, save the iterator pointing to its last element + * @param memClk + * @param begin + * @return true if this batch is ready, otherwise false + */ +bool SMS::batchFormation(sc_time memClk, std::pair> &requestBuffer, + std::deque::iterator beginIter) +{ + if (requestBuffer.second.empty()) + { + return false; + } + + if (requestBuffer.second.end() == beginIter) + { + return false; + } + + if (MPKCs[requestBuffer.first] < LOW_MPKC || isSystemLightlyLoaded()) + { + // bypass requests by forming batch with only one request (threshold age is ZERO) + readyBatchIters[requestBuffer.first].push_back(beginIter); + return true; + } + else + { + // forming batch with FIFO size & threshold age constraints + auto firstDifferentRowAccessReqIter = beginIter; + Row firstRow = DramExtension::getRow(*beginIter); + while (firstDifferentRowAccessReqIter != requestBuffer.second.end() + && DramExtension::getRow(*firstDifferentRowAccessReqIter) == firstRow) + { + firstDifferentRowAccessReqIter++; + } + + // deem this batch ready + if ((firstDifferentRowAccessReqIter != requestBuffer.second.end()) + || isExceededReqBufferSize(requestBuffer.first) + || isThresholdAgeExceeded(requestBuffer.first, memClk, beginIter, + firstDifferentRowAccessReqIter)) + { + firstDifferentRowAccessReqIter--; + readyBatchIters[requestBuffer.first].push_back(firstDifferentRowAccessReqIter); + debugManager.printDebugMessage(name(), + "Deem batch ready - thread " + to_string(requestBuffer.first.ID())); + return true; + } + else + { + return false; + } + } +} + +void SMS::multiBatchFormation(sc_time memClk) +{ + for (auto& requestBuffer : requestBuffers) + { + bool formed; + do + { + if (readyBatchIters[requestBuffer.first].empty()) + { + formed = batchFormation(memClk, (std::pair>&)requestBuffer, requestBuffer.second.begin()); + } + else + { + formed = batchFormation(memClk, (std::pair>&)requestBuffer, readyBatchIters[requestBuffer.first].back() + 1); + } + } while (formed); + } +} + +gp* SMS::getPendingRequest(Bank bank) +{ + for (auto& requestBuffer : requestBuffers) { + for (auto& request : requestBuffer.second) { + if (DramExtension::getBank(request) == bank) { + return request; + } + } + } + return NULL; +} diff --git a/DRAMSys/simulator/src/controller/scheduler/SMS.h b/DRAMSys/simulator/src/controller/scheduler/SMS.h new file mode 100644 index 00000000..2843b990 --- /dev/null +++ b/DRAMSys/simulator/src/controller/scheduler/SMS.h @@ -0,0 +1,84 @@ +#ifndef SMS_H +#define SMS_H + +#include +#include +#include "sysc/utils/sc_report.h" +#include "IScheduler.h" +#include "../core/ControllerCore.h" +#include "../core/configuration/Configuration.h" +#include "../../common/dramExtension.h" +#include "../../common/DebugManager.h" + +#define LOW_SYSTEM_LOAD 16 +#define LOW_MPKC 1 +#define MEDIUM_MPKC 10 +#define MEDIUM_THRESHOLD_AGE 50 +#define HIGH_THRESHOLD_AGE 200 +#define MPKC_RESET_CYCLE 10000 + +using namespace std; +typedef std::deque::iterator gp_deque_iterator; + +/** + * SMS - Staged Memory Scheduler involves 3 steps: + * 1. Arrage request in to each buffer of each thread + * 2. Forming ready batches for each thread, i.e all requests access the same row. The batch is deemed + * ready when the next request accesses different row OR When the buffer is full OR When this batch + * is too old + * 3. Send batches to bank buffers. The rules to send batches are Shortest-Job-First OR Round-Robin + * How we select the rule depends on the probability we setup earlier. + */ +class SMS: public sc_module, public IScheduler +{ +public: + SMS(sc_module_name /*_name*/, ControllerCore &controllerCore, unsigned int SJFprobability) : IScheduler(controllerCore), SJFprobability(SJFprobability), debugManager(DebugManager::getInstance()) + { + // initialize selected thread iterator + lastSelectedThread = readyBatchIters.end(); + SC_THREAD(batchScheduler); + } + SC_HAS_PROCESS(SMS); + + virtual ~SMS() + { + } + + virtual void schedule(gp *payload) override; + virtual std::pair getNextRequest(Bank bank) override; + virtual gp* getPendingRequest(Bank bank) override; + + void batchScheduler(); + +private: + std::map> requestBuffers; + std::map> bankBuffers; + std::map> readyBatchIters; + + std::map inFlightMemRequestCounter; + std::map cacheMisses; + std::map MPKCs; + unsigned int SJFprobability; + + std::map>::iterator lastSelectedThread; + sc_event newRequest; + + DebugManager& debugManager; + + bool batchFormation(sc_time memClk, std::pair> &requestBuffer, std::deque::iterator beginIter); + void multiBatchFormation(sc_time memClk); + bool pickSJF(); + bool pickRR(); + void drain(sc_time memClk, std::deque::iterator last); + + bool existLowIntensityThread(); + bool isSystemLightlyLoaded(); + bool isThresholdAgeExceeded(Thread thread, sc_time memClk, std::deque::iterator begin, std::deque::iterator end); + bool isExceededReqBufferSize(Thread thread); + void updateMPKCs(sc_time memClk); + + bool isRequestBuffersEmpty(); + bool existReadyBatches(); +}; + +#endif // SMS_H 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 41b80d42..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,42 +234,49 @@ 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; - for (auto controller : controllers) - { - delete controller; - } - for (auto dram : drams) { delete dram; @@ -264,6 +291,11 @@ DRAMSys::~DRAMSys() { delete tlmChecker; } + + for (auto controller : controllers) + { + delete controller; + } } void DRAMSys::report(string message) 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 fa3d9dec..61d5f941 100644 --- a/DRAMSys/simulator/src/simulation/Dram.h +++ b/DRAMSys/simulator/src/simulation/Dram.h @@ -92,6 +92,11 @@ 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; + std::uint64_t memorySize = Configuration::getInstance().getSimMemSizeInBytes(); // allocate and model storage of one DRAM channel using memory map memory = (unsigned char *)mmap(NULL, memorySize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0); 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/DRAMSys/simulator/src/simulation/TracePlayerListener.h b/DRAMSys/simulator/src/simulation/TracePlayerListener.h index 95c52773..bec9f043 100644 --- a/DRAMSys/simulator/src/simulation/TracePlayerListener.h +++ b/DRAMSys/simulator/src/simulation/TracePlayerListener.h @@ -43,6 +43,7 @@ class TracePlayerListener public: virtual void tracePlayerTerminates() = 0; virtual void transactionFinished() = 0; + virtual ~TracePlayerListener(){}; }; #endif // TRACEPLAYERLISTENER_H diff --git a/DRAMSys/simulator/src/simulation/TraceSetup.cpp b/DRAMSys/simulator/src/simulation/TraceSetup.cpp index 56df4b14..951b6360 100644 --- a/DRAMSys/simulator/src/simulation/TraceSetup.cpp +++ b/DRAMSys/simulator/src/simulation/TraceSetup.cpp @@ -96,8 +96,6 @@ traceSetup::traceSetup(std::string uri, NumberOfTracePlayers = devices->size(); } - - void traceSetup::tracePlayerTerminates() { finishedTracePlayers++; diff --git a/DRAMSys/simulator/src/simulation/TraceSetup.h b/DRAMSys/simulator/src/simulation/TraceSetup.h index a9f0b8e5..a11b4abe 100644 --- a/DRAMSys/simulator/src/simulation/TraceSetup.h +++ b/DRAMSys/simulator/src/simulation/TraceSetup.h @@ -53,6 +53,7 @@ public: virtual void tracePlayerTerminates() override; virtual void transactionFinished() override; + virtual ~traceSetup(){}; private: unsigned int NumberOfTracePlayers; diff --git a/DRAMSys/simulator/src/simulation/main.cpp b/DRAMSys/simulator/src/simulation/main.cpp index 18e00f77..60246caf 100644 --- a/DRAMSys/simulator/src/simulation/main.cpp +++ b/DRAMSys/simulator/src/simulation/main.cpp @@ -78,15 +78,15 @@ int sc_main(int argc, char **argv) std::vector players; // Instantiate DRAMSys: - DRAMSys dramSys("DRAMSys", SimulationXML, resources); + DRAMSys *dramSys = new DRAMSys("DRAMSys", SimulationXML, resources); // Instantiate STL Players: - traceSetup(SimulationXML, resources, &players); + traceSetup *ts = new traceSetup(SimulationXML, resources, &players); // Bind STL Players with DRAMSys: for(auto& p : players) { - p->iSocket.bind(dramSys.tSocket); + p->iSocket.bind(dramSys->tSocket); } // Store the starting of the simulation in wallclock time: @@ -105,5 +105,8 @@ int sc_main(int argc, char **argv) double elapsed_secs = double(clock() - simStartTime) / CLOCKS_PER_SEC; cout << "Simulation took " + to_string(elapsed_secs) + " seconds" << endl; + delete dramSys; + delete ts; + return 0; } 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**