From 3a51b695e8c881c599a9e8a2f9a6ac669374c5aa Mon Sep 17 00:00:00 2001 From: "Felipe S. Prado" Date: Mon, 26 Nov 2018 13:35:48 +0100 Subject: [PATCH 01/97] Retention time tolerance --- DRAMSys/traceAnalyzer/scripts/tests.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/DRAMSys/traceAnalyzer/scripts/tests.py b/DRAMSys/traceAnalyzer/scripts/tests.py index 27cb71a5..2b2b00b4 100755 --- a/DRAMSys/traceAnalyzer/scripts/tests.py +++ b/DRAMSys/traceAnalyzer/scripts/tests.py @@ -529,6 +529,10 @@ def max_time_without_ref(connection): else: maxTimeWithoutRef = dramconfig.tREFI + dramconfig.tRP + tolerance = 0.05 + + maxTimeWithoutRef = maxTimeWithoutRef + dramconfig.tREFI*tolerance + for row in result: timeBetweenRefs = row[0] - prevrow[1] if (timeBetweenRefs > maxTimeWithoutRef): From 33192eb57939c4bf38ec7cb63aa7156632ef0076 Mon Sep 17 00:00:00 2001 From: "Felipe S. Prado" Date: Mon, 26 Nov 2018 13:38:47 +0100 Subject: [PATCH 02/97] SREF phases taken into account when checking the maximum time without refresh --- DRAMSys/traceAnalyzer/scripts/tests.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/DRAMSys/traceAnalyzer/scripts/tests.py b/DRAMSys/traceAnalyzer/scripts/tests.py index 2b2b00b4..501ce151 100755 --- a/DRAMSys/traceAnalyzer/scripts/tests.py +++ b/DRAMSys/traceAnalyzer/scripts/tests.py @@ -512,11 +512,12 @@ def max_number_ref_burst(connection): return TestSuceeded() +@test @test def max_time_without_ref(connection): - """Checks that the maximum time allowed between REFA commands""" + """Checks that the maximum time allowed between REFA/SREF commands is not exceeded""" cursor = connection.cursor() - query = """SELECT PhaseBegin, PhaseEnd FROM phases WHERE PhaseName = 'REFA' """ + query = """SELECT PhaseBegin, PhaseEnd FROM phases WHERE PhaseName = 'REFA' OR PhaseName = 'SREF' """ prevrow = [0] * 2 flexibleRef = getFlexibleRef(connection) maxRefBurst = getMaxRefBurst(connection) From 59ed8995065d1a39c84451f1083c79f43b477d8d Mon Sep 17 00:00:00 2001 From: "Felipe S. Prado" Date: Mon, 26 Nov 2018 14:32:29 +0100 Subject: [PATCH 03/97] WRA to ACT delay fixed --- .../controller/core/scheduling/checker/ActivateChecker.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/ActivateChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/ActivateChecker.cpp index 86a6b0a1..2e29c114 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/ActivateChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/ActivateChecker.cpp @@ -60,12 +60,6 @@ void ActivateChecker::delayToSatisfyConstraints(ScheduledCommand &command) const } else if (lastCommandOnBank.getCommand() == Command::ReadA) { command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), config.memSpec.tRTP + config.memSpec.tRP); - } else if (lastCommandOnBank.getCommand() == Command::WriteA) { - command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), - config.memSpec.tRP); - } else if (lastCommandOnBank.getCommand() == Command::ReadA) { - command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), - config.memSpec.tRTP + config.memSpec.tRP); } else if (lastCommandOnBank.getCommand() == Command::WriteA) { command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR + From 2357c8adabbc6bc771665b9ff82b3f5ae4913944 Mon Sep 17 00:00:00 2001 From: "Felipe S. Prado" Date: Mon, 26 Nov 2018 14:57:59 +0100 Subject: [PATCH 04/97] SREF-REFB and PRE-REFA added as valid phase transitions --- DRAMSys/traceAnalyzer/scripts/tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DRAMSys/traceAnalyzer/scripts/tests.py b/DRAMSys/traceAnalyzer/scripts/tests.py index 27cb71a5..754bb37f 100755 --- a/DRAMSys/traceAnalyzer/scripts/tests.py +++ b/DRAMSys/traceAnalyzer/scripts/tests.py @@ -269,9 +269,9 @@ def phase_transitions_are_valid(connection): validTransitions['PDNAB'] = set(['PRE', 'RD', 'RDA', 'WR', 'WRA', 'REFB']) validTransitions['PDNPB'] = set(['ACT', 'REFB', 'SREFB']) - validTransitions['SREFB'] = set(['ACT']) + validTransitions['SREFB'] = set(['ACT', 'REFB']) else: - validTransitions['PRE'] = set(['ACT', 'PRE_ALL']) + validTransitions['PRE'] = set(['ACT', 'PRE_ALL', 'REFA']) validTransitions['PRE_ALL'] = set(['REFA', 'SREF']) validTransitions['ACT'] = set(['RD', 'RDA', 'WR', 'WRA', 'PRE_ALL']) From 4372084a59dc50ba62ec0bef184872fb5e071c4f Mon Sep 17 00:00:00 2001 From: "Felipe S. Prado" Date: Mon, 26 Nov 2018 18:04:51 +0100 Subject: [PATCH 05/97] PowerDownChecker fixed --- .../scheduling/checker/PowerDownChecker.cpp | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/PowerDownChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/PowerDownChecker.cpp index 6e066b61..6b92cd96 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/PowerDownChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/PowerDownChecker.cpp @@ -93,18 +93,26 @@ const // PDNP - Precharge Power Down // SREF - Self Refresh - // Get the last scheduled command on this bank - ScheduledCommand lastSchedCmdOnBank = state.getLastScheduledCommand(bank); + // Get the last scheduled command + ScheduledCommand lastSchedCmd; + if(Configuration::getInstance().BankwiseLogic) + { + lastSchedCmd = state.getLastScheduledCommand(bank); + } + else + { + lastSchedCmd = state.getLastScheduledCommand(); + } - if (lastSchedCmdOnBank.isValidCommand()) { - // Get the start time for the last scheduled command on this bank - sc_time lastSchedCmdOnBankStart = lastSchedCmdOnBank.getStart(); - // Get the last command on this bank itself - Command lastCmdBank = lastSchedCmdOnBank.getCommand(); + if (lastSchedCmd.isValidCommand()) { + // Get the start time for the last scheduled command + sc_time lastSchedCmdStart = lastSchedCmd.getStart(); + // Get the last command + Command lastCmd = lastSchedCmd.getCommand(); - timeConstraint = getTimeConstraintToEnterPowerDown(lastCmdBank, pdnCmd); + timeConstraint = getTimeConstraintToEnterPowerDown(lastCmd, pdnCmd); - command.establishMinDistanceFromStart(lastSchedCmdOnBankStart, timeConstraint); + command.establishMinDistanceFromStart(lastSchedCmdStart, timeConstraint); } } else if (pdnCmd == Command::PDNAX) { From e5ecef68e13e9a9383105a2ac8b56af0426c0d88 Mon Sep 17 00:00:00 2001 From: "Felipe S. Prado" Date: Fri, 30 Nov 2018 12:00:38 +0100 Subject: [PATCH 06/97] Players TLM Checkers --- DRAMSys/library/src/simulation/DRAMSys.h | 3 +++ DRAMSys/simulator/main.cpp | 16 ++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/DRAMSys/library/src/simulation/DRAMSys.h b/DRAMSys/library/src/simulation/DRAMSys.h index 25bf4bad..774e60d3 100644 --- a/DRAMSys/library/src/simulation/DRAMSys.h +++ b/DRAMSys/library/src/simulation/DRAMSys.h @@ -58,6 +58,9 @@ class DRAMSys: public sc_module public: tlm_utils::multi_passthrough_target_socket tSocket; + std::vector*> + playersTlmCheckers; + sc_event terminateSimulation; SC_HAS_PROCESS(DRAMSys); diff --git a/DRAMSys/simulator/main.cpp b/DRAMSys/simulator/main.cpp index d2716f80..956f373e 100644 --- a/DRAMSys/simulator/main.cpp +++ b/DRAMSys/simulator/main.cpp @@ -93,8 +93,20 @@ int sc_main(int argc, char **argv) traceSetup *ts = new traceSetup(SimulationXML, resources, &players); // Bind STL Players with DRAMSys: - for (auto &p : players) { - p->iSocket.bind(dramSys->tSocket); + for (size_t i = 0; i < players.size(); i++) { + if(Configuration::getInstance().CheckTLM2Protocol) + { + string str = "TLMCheckerPlayer" + std::to_string(i); + tlm_utils::tlm2_base_protocol_checker<> *playerTlmChecker = + new tlm_utils::tlm2_base_protocol_checker<>(str.c_str()); + dramSys->playersTlmCheckers.push_back(playerTlmChecker); + players[i]->iSocket.bind(dramSys->playersTlmCheckers[i]->target_socket); + dramSys->playersTlmCheckers[i]->initiator_socket.bind(dramSys->tSocket); + } + else + { + players[i]->iSocket.bind(dramSys->tSocket); + } } // Store the starting of the simulation in wallclock time: From 5441160b13ff05a0cd5b98cb572698426694ec70 Mon Sep 17 00:00:00 2001 From: Johannes Feldmann Date: Mon, 17 Dec 2018 11:08:49 +0100 Subject: [PATCH 07/97] Added Code coverage --- .gitlab-ci.yml | 9 ++++++++- DRAMSys/library/library.pro | 4 ++++ DRAMSys/library/src/common/third_party/googletest | 1 + DRAMSys/simulator/simulator.pro | 4 ++++ 4 files changed, 17 insertions(+), 1 deletion(-) create mode 160000 DRAMSys/library/src/common/third_party/googletest diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ba3576c0..1f8197c2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,6 +7,7 @@ stages: - build - WIDEIO - DDR3 + - Coverage cache: paths: @@ -22,7 +23,13 @@ build: - cd build - qmake ../DRAMSys/DRAMSys.pro - make -j4 - + + coverage: + stage: coverage + coverage: '/^TOTAL.*\s+(\d+\%)$/' + script: + - gcovr -r build/ + include: - '/DRAMSys/tests/DDR3/ci.yml' - '/DRAMSys/tests/WIDEIO/ci.yml' diff --git a/DRAMSys/library/library.pro b/DRAMSys/library/library.pro index 84267536..58d3037b 100644 --- a/DRAMSys/library/library.pro +++ b/DRAMSys/library/library.pro @@ -58,11 +58,15 @@ DEFINES += SC_INCLUDE_DYNAMIC_PROCESSES unix:!macx { QMAKE_CXXFLAGS += -std=c++11 -O0 -g + QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage -fPIC -O0 + QMAKE_LFLAGS += -lgcov --coverage } macx: { CONFIG += c++11 QMAKE_CXXFLAGS += -std=c++0x -stdlib=libc++ -O0 -g + QMAKE_CXXFLAGS += --coverage + QMAKE_LFLAGS += --coverage } QMAKE_CXXFLAGS += -isystem $${systemc_home}/include diff --git a/DRAMSys/library/src/common/third_party/googletest b/DRAMSys/library/src/common/third_party/googletest new file mode 160000 index 00000000..6ef59138 --- /dev/null +++ b/DRAMSys/library/src/common/third_party/googletest @@ -0,0 +1 @@ +Subproject commit 6ef59138137280ffb3c01f41f527abc2bd3249d0 diff --git a/DRAMSys/simulator/simulator.pro b/DRAMSys/simulator/simulator.pro index b5b297cf..dd592f3d 100644 --- a/DRAMSys/simulator/simulator.pro +++ b/DRAMSys/simulator/simulator.pro @@ -29,11 +29,15 @@ DEFINES += SC_INCLUDE_DYNAMIC_PROCESSES unix:!macx { QMAKE_CXXFLAGS += -std=c++11 -O0 -g + QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage -fPIC -O0 + QMAKE_LFLAGS += -lgcov --coverage } macx: { CONFIG += c++11 QMAKE_CXXFLAGS += -std=c++0x -stdlib=libc++ -O0 -g + QMAKE_CXXFLAGS += --coverage + QMAKE_LFLAGS += --coverage } INCLUDEPATH += ../library/src/simulation/ From dbdb4026ece5e72d9b96ae123644f445117b6268 Mon Sep 17 00:00:00 2001 From: Johannes Feldmann Date: Mon, 17 Dec 2018 11:12:14 +0100 Subject: [PATCH 08/97] Fixed typos in gitlab-ci --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1f8197c2..ac93cca1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -24,8 +24,8 @@ build: - qmake ../DRAMSys/DRAMSys.pro - make -j4 - coverage: - stage: coverage +coverage: + stage: Coverage coverage: '/^TOTAL.*\s+(\d+\%)$/' script: - gcovr -r build/ From 002925bc25b7a2ff658d6d456901e19eca992209 Mon Sep 17 00:00:00 2001 From: Johannes Feldmann Date: Mon, 17 Dec 2018 11:20:20 +0100 Subject: [PATCH 09/97] Removed google unit test framework --- DRAMSys/library/src/common/third_party/googletest | 1 - 1 file changed, 1 deletion(-) delete mode 160000 DRAMSys/library/src/common/third_party/googletest diff --git a/DRAMSys/library/src/common/third_party/googletest b/DRAMSys/library/src/common/third_party/googletest deleted file mode 160000 index 6ef59138..00000000 --- a/DRAMSys/library/src/common/third_party/googletest +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6ef59138137280ffb3c01f41f527abc2bd3249d0 From 037a9686a717c0a08ef413524f40c37de9a378fa Mon Sep 17 00:00:00 2001 From: Johannes Feldmann Date: Tue, 18 Dec 2018 09:39:48 +0100 Subject: [PATCH 10/97] Parallel Code Coverage for CI --- .gitlab-ci.yml | 7 ++++++- DRAMSys/tests/DDR3/ci.yml | 13 +++++++++++++ DRAMSys/tests/WIDEIO/ci.yml | 5 ++++- README.md | 2 +- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ac93cca1..df341f76 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -23,12 +23,17 @@ build: - cd build - qmake ../DRAMSys/DRAMSys.pro - make -j4 + - mkdir -p coverage coverage: stage: Coverage coverage: '/^TOTAL.*\s+(\d+\%)$/' script: - - gcovr -r build/ + - lcov `find coverage -type f -exec echo "-a {}" \;` -o coverage/final.out + artifacts: + paths: + - coverage/final.out + include: - '/DRAMSys/tests/DDR3/ci.yml' diff --git a/DRAMSys/tests/DDR3/ci.yml b/DRAMSys/tests/DDR3/ci.yml index 06cdadfa..7462848f 100644 --- a/DRAMSys/tests/DDR3/ci.yml +++ b/DRAMSys/tests/DDR3/ci.yml @@ -10,9 +10,12 @@ example_ddr3: - perl -e 'if(`sqldiff ../../DRAMSys/tests/DDR3/expected/ddr3-example_ddr3_ch0.tdb ddr3-example_ddr3_ch0.tdb` eq "") {exit(0)} else {exit(-1)}' - cd ../traceAnalyzer - python3 ../../DRAMSys/traceAnalyzer/scripts/tests.py ../simulator/ddr3-example_ddr3_ch0.tdb | if ! grep "failed"; then exit 0; else exit 1; fi + # Run Code Coverage + - lcov -c -d build/ -o coverage/{$CI_JOB_NAME}.out artifacts: paths: - build/simulator/ddr3-example_ddr3_ch0.tdb + - coverage/{$CI_JOB_NAME}.out expire_in: 2 days # Testing Reordering with FR_FCFS Scheduling Algorithm: @@ -27,12 +30,15 @@ fr_fcfs: - perl -e 'if(`sqldiff ../../DRAMSys/tests/DDR3/expected/ddr3-fr_fcfs_ddr3_ch0.tdb ddr3-fr_fcfs_ddr3_ch0.tdb` eq "") {exit(0)} else {exit(-1)}' - cd ../traceAnalyzer - python3 ../../DRAMSys/traceAnalyzer/scripts/tests.py ../simulator/ddr3-fr_fcfs_ddr3_ch0.tdb | if ! grep "failed"; then exit 0; else exit 1; fi + # Run Code Coverage + - lcov -c -d build/ -o coverage/{$CI_JOB_NAME}.out allow_failure: true # TODO should be removed after first tests artifacts: paths: - build/simulator/ddr3-fr_fcfs_ddr3_ch0.tdb + - coverage/{$CI_JOB_NAME}.out expire_in: 2 days # Testing with TLM Protocol Cchecker @@ -42,3 +48,10 @@ protocol_checker: - cd build/simulator - ./DRAMSys ../../DRAMSys/tests/DDR3/simulations/ddr3-protocol_checker.xml ../../DRAMSys/tests/DDR3/ - echo "TODO" + # Run Code Coverage + - lcov -c -d build/ -o coverage/{$CI_JOB_NAME}.out + + artifacts: + paths: + - coverage/{$CI_JOB_NAME}.out + expire_in: 2 days diff --git a/DRAMSys/tests/WIDEIO/ci.yml b/DRAMSys/tests/WIDEIO/ci.yml index 76ca5555..445a8596 100644 --- a/DRAMSys/tests/WIDEIO/ci.yml +++ b/DRAMSys/tests/WIDEIO/ci.yml @@ -15,7 +15,9 @@ example_wideio: - python3 ../../DRAMSys/traceAnalyzer/scripts/tests.py ../simulator/wideio-example_wideio_ch1.tdb | if ! grep "failed"; then exit 0; else exit 1; fi - python3 ../../DRAMSys/traceAnalyzer/scripts/tests.py ../simulator/wideio-example_wideio_ch2.tdb | if ! grep "failed"; then exit 0; else exit 1; fi - python3 ../../DRAMSys/traceAnalyzer/scripts/tests.py ../simulator/wideio-example_wideio_ch3.tdb | if ! grep "failed"; then exit 0; else exit 1; fi - + # Run Code Coverage + - lcov -c -d build/ -o coverage/{$CI_JOB_NAME}.out + allow_failure: true # TODO: should be removed once the problems are fixed! artifacts: @@ -24,5 +26,6 @@ example_wideio: - build/simulator/wideio-example_wideio_ch1.tdb - build/simulator/wideio-example_wideio_ch2.tdb - build/simulator/wideio-example_wideio_ch3.tdb + - coverage/{$CI_JOB_NAME}.out expire_in: 2 days diff --git a/README.md b/README.md index 22db70c4..ac7101e3 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ framework that consists of models reflecting the DRAM functionality, power consumption, temperature behaviour and retention time errors. Pipeline Status: [![pipeline status](https://git.eit.uni-kl.de/ems/astdm/dram.sys/badges/master/pipeline.svg)](https://git.eit.uni-kl.de/ems/astdm/dram.sys/commits/master) - +[![Coverage report](https://git.eit.uni-kl.de/ems/astdm/dram.sys/badges/master/coverage.svg?job=coverage)](https://git.eit.uni-kl.de/ems/astdm/dram.sys/commits/master) ## Basic Setup Open a terminal window, go to your home directory, create a directory for your From 732ae97bb3764ab68e5da46e2ecd553ff66e15aa Mon Sep 17 00:00:00 2001 From: Johannes Feldmann Date: Tue, 18 Dec 2018 09:52:10 +0100 Subject: [PATCH 11/97] Fixed Variable usage in CC --- DRAMSys/tests/DDR3/ci.yml | 12 ++++++------ DRAMSys/tests/WIDEIO/ci.yml | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/DRAMSys/tests/DDR3/ci.yml b/DRAMSys/tests/DDR3/ci.yml index 7462848f..a0270dc4 100644 --- a/DRAMSys/tests/DDR3/ci.yml +++ b/DRAMSys/tests/DDR3/ci.yml @@ -11,11 +11,11 @@ example_ddr3: - cd ../traceAnalyzer - python3 ../../DRAMSys/traceAnalyzer/scripts/tests.py ../simulator/ddr3-example_ddr3_ch0.tdb | if ! grep "failed"; then exit 0; else exit 1; fi # Run Code Coverage - - lcov -c -d build/ -o coverage/{$CI_JOB_NAME}.out + - lcov -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out artifacts: paths: - build/simulator/ddr3-example_ddr3_ch0.tdb - - coverage/{$CI_JOB_NAME}.out + - coverage/${CI_JOB_NAME}.out expire_in: 2 days # Testing Reordering with FR_FCFS Scheduling Algorithm: @@ -31,14 +31,14 @@ fr_fcfs: - cd ../traceAnalyzer - python3 ../../DRAMSys/traceAnalyzer/scripts/tests.py ../simulator/ddr3-fr_fcfs_ddr3_ch0.tdb | if ! grep "failed"; then exit 0; else exit 1; fi # Run Code Coverage - - lcov -c -d build/ -o coverage/{$CI_JOB_NAME}.out + - lcov -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out allow_failure: true # TODO should be removed after first tests artifacts: paths: - build/simulator/ddr3-fr_fcfs_ddr3_ch0.tdb - - coverage/{$CI_JOB_NAME}.out + - coverage/${CI_JOB_NAME}.out expire_in: 2 days # Testing with TLM Protocol Cchecker @@ -49,9 +49,9 @@ protocol_checker: - ./DRAMSys ../../DRAMSys/tests/DDR3/simulations/ddr3-protocol_checker.xml ../../DRAMSys/tests/DDR3/ - echo "TODO" # Run Code Coverage - - lcov -c -d build/ -o coverage/{$CI_JOB_NAME}.out + - lcov -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out artifacts: paths: - - coverage/{$CI_JOB_NAME}.out + - coverage/${CI_JOB_NAME}.out expire_in: 2 days diff --git a/DRAMSys/tests/WIDEIO/ci.yml b/DRAMSys/tests/WIDEIO/ci.yml index 445a8596..834eceb8 100644 --- a/DRAMSys/tests/WIDEIO/ci.yml +++ b/DRAMSys/tests/WIDEIO/ci.yml @@ -16,7 +16,7 @@ example_wideio: - python3 ../../DRAMSys/traceAnalyzer/scripts/tests.py ../simulator/wideio-example_wideio_ch2.tdb | if ! grep "failed"; then exit 0; else exit 1; fi - python3 ../../DRAMSys/traceAnalyzer/scripts/tests.py ../simulator/wideio-example_wideio_ch3.tdb | if ! grep "failed"; then exit 0; else exit 1; fi # Run Code Coverage - - lcov -c -d build/ -o coverage/{$CI_JOB_NAME}.out + - lcov -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out allow_failure: true # TODO: should be removed once the problems are fixed! @@ -26,6 +26,6 @@ example_wideio: - build/simulator/wideio-example_wideio_ch1.tdb - build/simulator/wideio-example_wideio_ch2.tdb - build/simulator/wideio-example_wideio_ch3.tdb - - coverage/{$CI_JOB_NAME}.out + - coverage/${CI_JOB_NAME}.out expire_in: 2 days From 40b1690ddf338b9115e6a68a09fef9b270a2aaa9 Mon Sep 17 00:00:00 2001 From: Johannes Feldmann Date: Tue, 18 Dec 2018 10:04:22 +0100 Subject: [PATCH 12/97] Fixed coverage directory --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index df341f76..7714db08 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -23,7 +23,7 @@ build: - cd build - qmake ../DRAMSys/DRAMSys.pro - make -j4 - - mkdir -p coverage + - mkdir -p ${CI_PROJECT_DIR}/coverage coverage: stage: Coverage From d7c6628eaa29b34d39a03c578230ce1af562c2fd Mon Sep 17 00:00:00 2001 From: Johannes Feldmann Date: Tue, 18 Dec 2018 10:21:12 +0100 Subject: [PATCH 13/97] Moved creation of directory coverage to jobs --- .gitlab-ci.yml | 3 +-- DRAMSys/tests/DDR3/ci.yml | 3 +++ DRAMSys/tests/WIDEIO/ci.yml | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7714db08..cdbd9165 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -23,11 +23,10 @@ build: - cd build - qmake ../DRAMSys/DRAMSys.pro - make -j4 - - mkdir -p ${CI_PROJECT_DIR}/coverage coverage: stage: Coverage - coverage: '/^TOTAL.*\s+(\d+\%)$/' + coverage: '/^\s*lines\s*\d+.\d+\%/' script: - lcov `find coverage -type f -exec echo "-a {}" \;` -o coverage/final.out artifacts: diff --git a/DRAMSys/tests/DDR3/ci.yml b/DRAMSys/tests/DDR3/ci.yml index a0270dc4..1ed5cf78 100644 --- a/DRAMSys/tests/DDR3/ci.yml +++ b/DRAMSys/tests/DDR3/ci.yml @@ -11,6 +11,7 @@ example_ddr3: - cd ../traceAnalyzer - python3 ../../DRAMSys/traceAnalyzer/scripts/tests.py ../simulator/ddr3-example_ddr3_ch0.tdb | if ! grep "failed"; then exit 0; else exit 1; fi # Run Code Coverage + - mkdir -p ${CI_PROJECT_DIR}/coverage - lcov -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out artifacts: paths: @@ -31,6 +32,7 @@ fr_fcfs: - cd ../traceAnalyzer - python3 ../../DRAMSys/traceAnalyzer/scripts/tests.py ../simulator/ddr3-fr_fcfs_ddr3_ch0.tdb | if ! grep "failed"; then exit 0; else exit 1; fi # Run Code Coverage + - mkdir -p ${CI_PROJECT_DIR}/coverage - lcov -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out allow_failure: true # TODO should be removed after first tests @@ -49,6 +51,7 @@ protocol_checker: - ./DRAMSys ../../DRAMSys/tests/DDR3/simulations/ddr3-protocol_checker.xml ../../DRAMSys/tests/DDR3/ - echo "TODO" # Run Code Coverage + - mkdir -p ${CI_PROJECT_DIR}/coverage - lcov -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out artifacts: diff --git a/DRAMSys/tests/WIDEIO/ci.yml b/DRAMSys/tests/WIDEIO/ci.yml index 834eceb8..02b5482e 100644 --- a/DRAMSys/tests/WIDEIO/ci.yml +++ b/DRAMSys/tests/WIDEIO/ci.yml @@ -16,6 +16,7 @@ example_wideio: - python3 ../../DRAMSys/traceAnalyzer/scripts/tests.py ../simulator/wideio-example_wideio_ch2.tdb | if ! grep "failed"; then exit 0; else exit 1; fi - python3 ../../DRAMSys/traceAnalyzer/scripts/tests.py ../simulator/wideio-example_wideio_ch3.tdb | if ! grep "failed"; then exit 0; else exit 1; fi # Run Code Coverage + - mkdir -p ${CI_PROJECT_DIR}/coverage - lcov -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out allow_failure: true # TODO: should be removed once the problems are fixed! From c3393e6d6439f2a6c4d68699e7d0573d45c4f7a8 Mon Sep 17 00:00:00 2001 From: Johannes Feldmann Date: Tue, 18 Dec 2018 10:52:45 +0100 Subject: [PATCH 14/97] After_script added to remove junk --- .gitlab-ci.yml | 4 +++- DRAMSys/tests/DDR3/ci.yml | 13 +++++++++++++ DRAMSys/tests/WIDEIO/ci.yml | 6 +++++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cdbd9165..3c464a75 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,6 +12,7 @@ stages: cache: paths: - build/ + - coverage/ build: stage: build @@ -23,7 +24,8 @@ build: - cd build - qmake ../DRAMSys/DRAMSys.pro - make -j4 - + - rm -r *.o + coverage: stage: Coverage coverage: '/^\s*lines\s*\d+.\d+\%/' diff --git a/DRAMSys/tests/DDR3/ci.yml b/DRAMSys/tests/DDR3/ci.yml index 1ed5cf78..e5cc8163 100644 --- a/DRAMSys/tests/DDR3/ci.yml +++ b/DRAMSys/tests/DDR3/ci.yml @@ -13,6 +13,11 @@ example_ddr3: # Run Code Coverage - mkdir -p ${CI_PROJECT_DIR}/coverage - lcov -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out + after_script: + - cd build/ + - rm -r *.gcno + - rm -r *.gcda + artifacts: paths: - build/simulator/ddr3-example_ddr3_ch0.tdb @@ -34,6 +39,10 @@ fr_fcfs: # Run Code Coverage - mkdir -p ${CI_PROJECT_DIR}/coverage - lcov -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out + after_script: + - cd build/ + - rm -r *.gcno + - rm -r *.gcda allow_failure: true # TODO should be removed after first tests @@ -53,6 +62,10 @@ protocol_checker: # Run Code Coverage - mkdir -p ${CI_PROJECT_DIR}/coverage - lcov -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out + after_script: + - cd build/ + - rm -r *.gcno + - rm -r *.gcda artifacts: paths: diff --git a/DRAMSys/tests/WIDEIO/ci.yml b/DRAMSys/tests/WIDEIO/ci.yml index 02b5482e..ba468038 100644 --- a/DRAMSys/tests/WIDEIO/ci.yml +++ b/DRAMSys/tests/WIDEIO/ci.yml @@ -18,7 +18,11 @@ example_wideio: # Run Code Coverage - mkdir -p ${CI_PROJECT_DIR}/coverage - lcov -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out - + after_script: + - cd build/ + - rm -r *.gcno + - rm -r *.gcda + allow_failure: true # TODO: should be removed once the problems are fixed! artifacts: From f34a257ce7b32c247dbe343754b3a66f1ba15359 Mon Sep 17 00:00:00 2001 From: Johannes Feldmann Date: Tue, 18 Dec 2018 10:57:49 +0100 Subject: [PATCH 15/97] Bugfix recursive deletion of files --- .gitlab-ci.yml | 2 +- DRAMSys/tests/DDR3/ci.yml | 12 ++++++------ DRAMSys/tests/WIDEIO/ci.yml | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3c464a75..03ea6838 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -24,7 +24,7 @@ build: - cd build - qmake ../DRAMSys/DRAMSys.pro - make -j4 - - rm -r *.o + - find . -name "*.o" -type f -delete coverage: stage: Coverage diff --git a/DRAMSys/tests/DDR3/ci.yml b/DRAMSys/tests/DDR3/ci.yml index e5cc8163..c25333ee 100644 --- a/DRAMSys/tests/DDR3/ci.yml +++ b/DRAMSys/tests/DDR3/ci.yml @@ -15,8 +15,8 @@ example_ddr3: - lcov -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out after_script: - cd build/ - - rm -r *.gcno - - rm -r *.gcda + - find . -name "*.gcno" -type f -delete + - find . -name "*.gcda" -type f -delete artifacts: paths: @@ -41,8 +41,8 @@ fr_fcfs: - lcov -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out after_script: - cd build/ - - rm -r *.gcno - - rm -r *.gcda + - find . -name "*.gcno" -type f -delete + - find . -name "*.gcda" -type f -delete allow_failure: true # TODO should be removed after first tests @@ -64,8 +64,8 @@ protocol_checker: - lcov -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out after_script: - cd build/ - - rm -r *.gcno - - rm -r *.gcda + - find . -name "*.gcno" -type f -delete + - find . -name "*.gcda" -type f -delete artifacts: paths: diff --git a/DRAMSys/tests/WIDEIO/ci.yml b/DRAMSys/tests/WIDEIO/ci.yml index ba468038..2afe10a9 100644 --- a/DRAMSys/tests/WIDEIO/ci.yml +++ b/DRAMSys/tests/WIDEIO/ci.yml @@ -20,8 +20,8 @@ example_wideio: - lcov -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out after_script: - cd build/ - - rm -r *.gcno - - rm -r *.gcda + - find . -name "*.gcno" -type f -delete + - find . -name "*.gcda" -type f -delete allow_failure: true # TODO: should be removed once the problems are fixed! From d293fe976339c48b1eb782a43c82a982b1bc2975 Mon Sep 17 00:00:00 2001 From: Johannes Feldmann Date: Tue, 18 Dec 2018 11:14:05 +0100 Subject: [PATCH 16/97] Redirected output of protocol checker to file --- .gitlab-ci.yml | 1 - DRAMSys/tests/DDR3/ci.yml | 8 ++++---- DRAMSys/tests/WIDEIO/ci.yml | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 03ea6838..30cc3412 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,7 +12,6 @@ stages: cache: paths: - build/ - - coverage/ build: stage: build diff --git a/DRAMSys/tests/DDR3/ci.yml b/DRAMSys/tests/DDR3/ci.yml index c25333ee..46a896dd 100644 --- a/DRAMSys/tests/DDR3/ci.yml +++ b/DRAMSys/tests/DDR3/ci.yml @@ -12,7 +12,7 @@ example_ddr3: - python3 ../../DRAMSys/traceAnalyzer/scripts/tests.py ../simulator/ddr3-example_ddr3_ch0.tdb | if ! grep "failed"; then exit 0; else exit 1; fi # Run Code Coverage - mkdir -p ${CI_PROJECT_DIR}/coverage - - lcov -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out + - lcov -q -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out after_script: - cd build/ - find . -name "*.gcno" -type f -delete @@ -38,7 +38,7 @@ fr_fcfs: - python3 ../../DRAMSys/traceAnalyzer/scripts/tests.py ../simulator/ddr3-fr_fcfs_ddr3_ch0.tdb | if ! grep "failed"; then exit 0; else exit 1; fi # Run Code Coverage - mkdir -p ${CI_PROJECT_DIR}/coverage - - lcov -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out + - lcov -q -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out after_script: - cd build/ - find . -name "*.gcno" -type f -delete @@ -57,11 +57,11 @@ protocol_checker: stage: DDR3 script: - cd build/simulator - - ./DRAMSys ../../DRAMSys/tests/DDR3/simulations/ddr3-protocol_checker.xml ../../DRAMSys/tests/DDR3/ + - ./DRAMSys ../../DRAMSys/tests/DDR3/simulations/ddr3-protocol_checker.xml ../../DRAMSys/tests/DDR3/ > output.txt - echo "TODO" # Run Code Coverage - mkdir -p ${CI_PROJECT_DIR}/coverage - - lcov -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out + - lcov -q -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out after_script: - cd build/ - find . -name "*.gcno" -type f -delete diff --git a/DRAMSys/tests/WIDEIO/ci.yml b/DRAMSys/tests/WIDEIO/ci.yml index 2afe10a9..b585010a 100644 --- a/DRAMSys/tests/WIDEIO/ci.yml +++ b/DRAMSys/tests/WIDEIO/ci.yml @@ -17,7 +17,7 @@ example_wideio: - python3 ../../DRAMSys/traceAnalyzer/scripts/tests.py ../simulator/wideio-example_wideio_ch3.tdb | if ! grep "failed"; then exit 0; else exit 1; fi # Run Code Coverage - mkdir -p ${CI_PROJECT_DIR}/coverage - - lcov -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out + - lcov -q -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out after_script: - cd build/ - find . -name "*.gcno" -type f -delete From 9b6a092892b0c8215e25c4f740b3981dec800927 Mon Sep 17 00:00:00 2001 From: Johannes Feldmann Date: Tue, 18 Dec 2018 11:38:44 +0100 Subject: [PATCH 17/97] *.gcno files will not be deleted anymore. --- .gitlab-ci.yml | 4 ++-- DRAMSys/tests/DDR3/ci.yml | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 30cc3412..f051ca39 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,7 +5,7 @@ variables: stages: - build - - WIDEIO +# - WIDEIO - DDR3 - Coverage @@ -37,4 +37,4 @@ coverage: include: - '/DRAMSys/tests/DDR3/ci.yml' - - '/DRAMSys/tests/WIDEIO/ci.yml' +# - '/DRAMSys/tests/WIDEIO/ci.yml' diff --git a/DRAMSys/tests/DDR3/ci.yml b/DRAMSys/tests/DDR3/ci.yml index 46a896dd..4d7b4d25 100644 --- a/DRAMSys/tests/DDR3/ci.yml +++ b/DRAMSys/tests/DDR3/ci.yml @@ -15,7 +15,7 @@ example_ddr3: - lcov -q -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out after_script: - cd build/ - - find . -name "*.gcno" -type f -delete +# - find . -name "*.gcno" -type f -delete - find . -name "*.gcda" -type f -delete artifacts: @@ -41,7 +41,7 @@ fr_fcfs: - lcov -q -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out after_script: - cd build/ - - find . -name "*.gcno" -type f -delete +# - find . -name "*.gcno" -type f -delete - find . -name "*.gcda" -type f -delete allow_failure: true # TODO should be removed after first tests @@ -64,7 +64,7 @@ protocol_checker: - lcov -q -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out after_script: - cd build/ - - find . -name "*.gcno" -type f -delete +# - find . -name "*.gcno" -type f -delete - find . -name "*.gcda" -type f -delete artifacts: From 8d0e08d0a372a6740473f0491c2a85c7bc5ed871 Mon Sep 17 00:00:00 2001 From: Johannes Feldmann Date: Tue, 18 Dec 2018 12:01:39 +0100 Subject: [PATCH 18/97] Using local caches to reduce runtime --- .gitlab-ci.yml | 11 ++++++++--- DRAMSys/tests/DDR3/ci.yml | 36 +++++++++++++++++++++++++++--------- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f051ca39..36b696fb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -9,9 +9,9 @@ stages: - DDR3 - Coverage -cache: - paths: - - build/ +#cache: +# paths: +# - build/ build: stage: build @@ -24,6 +24,11 @@ build: - qmake ../DRAMSys/DRAMSys.pro - make -j4 - find . -name "*.o" -type f -delete + cache: + key: build + paths: + - build/ + policy: push coverage: stage: Coverage diff --git a/DRAMSys/tests/DDR3/ci.yml b/DRAMSys/tests/DDR3/ci.yml index 4d7b4d25..6829d561 100644 --- a/DRAMSys/tests/DDR3/ci.yml +++ b/DRAMSys/tests/DDR3/ci.yml @@ -13,10 +13,16 @@ example_ddr3: # Run Code Coverage - mkdir -p ${CI_PROJECT_DIR}/coverage - lcov -q -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out - after_script: - - cd build/ +# after_script: +# - cd build/ # - find . -name "*.gcno" -type f -delete - - find . -name "*.gcda" -type f -delete +# - find . -name "*.gcda" -type f -delete + + cache: + key: build + paths: + - build/ + policy: pull artifacts: paths: @@ -39,10 +45,16 @@ fr_fcfs: # Run Code Coverage - mkdir -p ${CI_PROJECT_DIR}/coverage - lcov -q -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out - after_script: - - cd build/ +# after_script: +# - cd build/ # - find . -name "*.gcno" -type f -delete - - find . -name "*.gcda" -type f -delete +# - find . -name "*.gcda" -type f -delete + + cache: + key: build + paths: + - build/ + policy: pull allow_failure: true # TODO should be removed after first tests @@ -62,10 +74,16 @@ protocol_checker: # Run Code Coverage - mkdir -p ${CI_PROJECT_DIR}/coverage - lcov -q -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out - after_script: - - cd build/ +# after_script: +# - cd build/ # - find . -name "*.gcno" -type f -delete - - find . -name "*.gcda" -type f -delete +# - find . -name "*.gcda" -type f -delete + + cache: + key: build + paths: + - build/ + policy: pull artifacts: paths: From b1188981114223d3c43d25beb1b5110a5718c5f2 Mon Sep 17 00:00:00 2001 From: Johannes Feldmann Date: Tue, 18 Dec 2018 13:16:56 +0100 Subject: [PATCH 19/97] Empty files in coverage/ will be deleted --- .gitlab-ci.yml | 2 ++ DRAMSys/tests/DDR3/ci.yml | 1 + 2 files changed, 3 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 36b696fb..7e40509c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -34,6 +34,8 @@ coverage: stage: Coverage coverage: '/^\s*lines\s*\d+.\d+\%/' script: + # delete all empty files since they produce errors + - find coverage -size 0 -type f -delete - lcov `find coverage -type f -exec echo "-a {}" \;` -o coverage/final.out artifacts: paths: diff --git a/DRAMSys/tests/DDR3/ci.yml b/DRAMSys/tests/DDR3/ci.yml index 6829d561..4905c2ed 100644 --- a/DRAMSys/tests/DDR3/ci.yml +++ b/DRAMSys/tests/DDR3/ci.yml @@ -71,6 +71,7 @@ protocol_checker: - cd build/simulator - ./DRAMSys ../../DRAMSys/tests/DDR3/simulations/ddr3-protocol_checker.xml ../../DRAMSys/tests/DDR3/ > output.txt - echo "TODO" + - ls -lah # Run Code Coverage - mkdir -p ${CI_PROJECT_DIR}/coverage - lcov -q -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out From 2061877afa73cee4b85cd79e60a90a2480df748b Mon Sep 17 00:00:00 2001 From: Johannes Feldmann Date: Tue, 18 Dec 2018 13:48:37 +0100 Subject: [PATCH 20/97] CI Scripts cleaned up. ls output added. --- .gitlab-ci.yml | 11 ++++------- DRAMSys/tests/DDR3/ci.yml | 12 ------------ DRAMSys/tests/WIDEIO/ci.yml | 10 ++++++---- 3 files changed, 10 insertions(+), 23 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7e40509c..f6382baa 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,14 +5,10 @@ variables: stages: - build -# - WIDEIO + - WIDEIO - DDR3 - Coverage -#cache: -# paths: -# - build/ - build: stage: build script: @@ -32,10 +28,11 @@ build: coverage: stage: Coverage - coverage: '/^\s*lines\s*\d+.\d+\%/' + coverage: '/^\s*lines(.)*:\s*\d+.\d+\%/' script: # delete all empty files since they produce errors - find coverage -size 0 -type f -delete + - ls -lah - lcov `find coverage -type f -exec echo "-a {}" \;` -o coverage/final.out artifacts: paths: @@ -44,4 +41,4 @@ coverage: include: - '/DRAMSys/tests/DDR3/ci.yml' -# - '/DRAMSys/tests/WIDEIO/ci.yml' + - '/DRAMSys/tests/WIDEIO/ci.yml' diff --git a/DRAMSys/tests/DDR3/ci.yml b/DRAMSys/tests/DDR3/ci.yml index 4905c2ed..b92199d0 100644 --- a/DRAMSys/tests/DDR3/ci.yml +++ b/DRAMSys/tests/DDR3/ci.yml @@ -13,10 +13,6 @@ example_ddr3: # Run Code Coverage - mkdir -p ${CI_PROJECT_DIR}/coverage - lcov -q -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out -# after_script: -# - cd build/ -# - find . -name "*.gcno" -type f -delete -# - find . -name "*.gcda" -type f -delete cache: key: build @@ -45,10 +41,6 @@ fr_fcfs: # Run Code Coverage - mkdir -p ${CI_PROJECT_DIR}/coverage - lcov -q -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out -# after_script: -# - cd build/ -# - find . -name "*.gcno" -type f -delete -# - find . -name "*.gcda" -type f -delete cache: key: build @@ -75,10 +67,6 @@ protocol_checker: # Run Code Coverage - mkdir -p ${CI_PROJECT_DIR}/coverage - lcov -q -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out -# after_script: -# - cd build/ -# - find . -name "*.gcno" -type f -delete -# - find . -name "*.gcda" -type f -delete cache: key: build diff --git a/DRAMSys/tests/WIDEIO/ci.yml b/DRAMSys/tests/WIDEIO/ci.yml index b585010a..7fc1ee7b 100644 --- a/DRAMSys/tests/WIDEIO/ci.yml +++ b/DRAMSys/tests/WIDEIO/ci.yml @@ -18,10 +18,12 @@ example_wideio: # Run Code Coverage - mkdir -p ${CI_PROJECT_DIR}/coverage - lcov -q -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out - after_script: - - cd build/ - - find . -name "*.gcno" -type f -delete - - find . -name "*.gcda" -type f -delete + + cache: + key: build + paths: + - build/ + policy: pull allow_failure: true # TODO: should be removed once the problems are fixed! From 61342897ab0d58cdcef6690a2d151c778d9b9916 Mon Sep 17 00:00:00 2001 From: Johannes Feldmann Date: Tue, 18 Dec 2018 17:24:15 +0100 Subject: [PATCH 21/97] Changed code coverage output and regex --- .gitlab-ci.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f6382baa..b9e0622e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -28,12 +28,13 @@ build: coverage: stage: Coverage - coverage: '/^\s*lines(.)*:\s*\d+.\d+\%/' + coverage: '/Total:\|(\d+\.?\d+\%)/' script: # delete all empty files since they produce errors - find coverage -size 0 -type f -delete - - ls -lah + - ls coverage/ -lah - lcov `find coverage -type f -exec echo "-a {}" \;` -o coverage/final.out + - lcov --list coverage/final.out artifacts: paths: - coverage/final.out From 0f0963c27e38dfcabfcdcd1f6ac2658713b4f71c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Fri, 25 Jan 2019 11:56:40 +0100 Subject: [PATCH 22/97] Notes for Elwetritsch users --- README.md | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/README.md b/README.md index 22db70c4..3e3e3d65 100644 --- a/README.md +++ b/README.md @@ -1707,6 +1707,91 @@ If you need help please contact Matthias Jung. Users can profit of running multiple simulations automatically with [gem5ilva](DRAMSys/library/resources/scripts/DRAMSylva/gem5ilva.sh). +### Notes for Elwetritsch users + +For using DRAMSys + gem5 on the Elwetritsch gem5 can be installed with +convenience scripts provided by +[gem5.TnT](https://github.com/tukl-msd/gem5.TnT). + +[gem5.TnT](https://github.com/tukl-msd/gem5.TnT) provides convenience scripts +to create disk images too. The creation of disk images for gem5 requires +superuser privilege. A solution is to copy locally created the disk images +locally to Elwetritsch (e.g., scp or mounting a folder, etc.). Since there is +no compilation copying disk images should not incur in incompatibility +problems. + +Regarding dependencies for building DRAMSys and gem5, the scripts provided in +[DRAMSylva](DRAMSys/library/resources/scripts/DRAMSylva), when running on +Elwetritsch, will load the required modules automatically. + +On gem5.TnT repository open a gem5.TnT config file. + +```bash +$ vim common/defaults.in +``` + +Note the variable ROOTDIR. Its default value is readonly +ROOTDIR=$HOME/gem5_tnt. That means that gem5.TnT will download to +$HOME/gem5_tnt. + +Currently on Elwetritsch the space one can use in $HOME is limited to some +tens of GiB. + +One can create a symlink pointing to /scratch/$USER/gem5_tnt (/scratch/$USER +is a place where lots of space are available). + +```bash +$ cd $SCRATCH +$ mkdir gem5_tnt +$ cd +$ ln -s /scratch/$USER/gem5_tnt +``` + +On gem5.TnT repository use the commands below to get files and build gem5: + +```bash +$ ./get_essential_fs.sh +$ ./get_benchmarks.sh +$ ./get_extra_fs.sh +$ ./build_gem5.sh +``` + +Example of a functional ~/.bashrc on Elwetritsch: + +```bash +# User specific aliases and functions +# SystemC home +export SYSTEMC_HOME=$HOME/repos/systemc-2.3.1a +# SystemC target architecture +export SYSTEMC_TARGET_ARCH=linux64 +export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${SYSTEMC_HOME}/lib-linux64 + +# Qwt lib +export LIBQWT_HOME=$HOME/repos/qwt-6.1/lib +export LIBQWT_HEADERS=$HOME/repos/qwt-6.1/src +export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}$LIBQWT_HOME + +# Python lib +export LIBPYTHON_VERSION="3.4m" +export PYTHON_HOME=/usr/lib64 +export PYTHON_HEADERS=/usr/include/python3.4m + +# Gem5 + DRAMsys +export GEM5=$HOME/gem5_tnt/gem5 + +# Gem5 SystemC/TLM2.0 coupling (see also: $HOME/gem5_tnt/gem5/util/tlm/README) +export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${HOME}/gem5_tnt/gem5/build/ARM +export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${SYSTEMC_HOME}/lib-$SYSTEMC_TARGET_ARCH +export PKG_CONFIG_PATH=${PKG_CONFIG_PATH}:${SYSTEMC_HOME}/lib-$SYSTEMC_TARGET_ARCH/pkgconfig + +# M5_PATH for gem5 +export M5_PATH=$HOME/gem5_tnt/full_system/arm/aarch-system-20180409 + +# Do not close my terminal when inactive after a timeout +unset TMOUT +``` + + ## References [1] TLM Modelling of 3D Stacked Wide I/O DRAM Subsystems, A Virtual Platform for Memory Controller Design Space Exploration From e979874e206388a35ecec32f45fd8e37167af130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Fri, 25 Jan 2019 12:57:58 +0100 Subject: [PATCH 23/97] Doc++ more info about Elwetritsch cluster usage --- README.md | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 3e3e3d65..9fada0ed 100644 --- a/README.md +++ b/README.md @@ -1707,17 +1707,26 @@ If you need help please contact Matthias Jung. Users can profit of running multiple simulations automatically with [gem5ilva](DRAMSys/library/resources/scripts/DRAMSylva/gem5ilva.sh). -### Notes for Elwetritsch users +### Notes for [Elwetritsch](https://elwe.rhrk.uni-kl.de/) Users -For using DRAMSys + gem5 on the Elwetritsch gem5 can be installed with -convenience scripts provided by + +Firstly, take a look at [High Performance Computing at the TU +Kaiserslautern](https://elwe.rhrk.uni-kl.de/). + +After that, please give yourself a change to learn a bit about [Batch Usage at +RHRK TU Kaiserslautern](https://elwe.rhrk.uni-kl.de/elwetritsch/batch.shtml). +This will probably save you some time later on. + +When using DRAMSys + gem5 on the [Elwetritsch](https://elwe.rhrk.uni-kl.de/) +gem5 can be installed with convenience scripts provided by [gem5.TnT](https://github.com/tukl-msd/gem5.TnT). -[gem5.TnT](https://github.com/tukl-msd/gem5.TnT) provides convenience scripts -to create disk images too. The creation of disk images for gem5 requires -superuser privilege. A solution is to copy locally created the disk images -locally to Elwetritsch (e.g., scp or mounting a folder, etc.). Since there is -no compilation copying disk images should not incur in incompatibility +[gem5.TnT](https://github.com/tukl-msd/gem5.TnT) also provides convenience scripts +to create gem5 disk images with benchmarking programs embedded. The creation +of disk images for gem5 requires superuser privilege. A solution is to copy +(e.g., using scp or mounting a folder, etc.) the locally created disk images +to Elwetritsch. Since there is no compilation involved, copying disk images +created in one machine to another machine should not incur in incompatibility problems. Regarding dependencies for building DRAMSys and gem5, the scripts provided in @@ -1730,15 +1739,14 @@ On gem5.TnT repository open a gem5.TnT config file. $ vim common/defaults.in ``` -Note the variable ROOTDIR. Its default value is readonly -ROOTDIR=$HOME/gem5_tnt. That means that gem5.TnT will download to -$HOME/gem5_tnt. +Note the variable **ROOTDIR**. Its default value is *ROOTDIR=$HOME/gem5_tnt*. +That means that gem5.TnT will download to *$HOME/gem5_tnt*. -Currently on Elwetritsch the space one can use in $HOME is limited to some -tens of GiB. +Currently the space one can use in its Elwetrich *$HOME* folder is limited to +a few tens of GiB. Nevertheless, a directory **/scratch/$USER** is provided +with less space restrictions. -One can create a symlink pointing to /scratch/$USER/gem5_tnt (/scratch/$USER -is a place where lots of space are available). +One can create a symlink pointing to **/scratch/$USER/gem5_tnt**. ```bash $ cd $SCRATCH @@ -1791,6 +1799,12 @@ export M5_PATH=$HOME/gem5_tnt/full_system/arm/aarch-system-20180409 unset TMOUT ``` +[SLURM](https://slurm.schedmd.com/overview.html) **job scripts** are available +inside the [DRAMSylva](DRAMSys/library/resources/scripts/DRAMSylva) folder. +They can be used directly without changes or as examples on how to start jobs +using nodes of the Elwetritsch cluster. Of course, one can create his/her own +job scripts. + ## References From 629e6fad66aedf551ff779563e71c7cfac1b93b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Mon, 28 Jan 2019 12:38:54 +0100 Subject: [PATCH 24/97] Doc updated --- README.md | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 9fada0ed..04a58785 100644 --- a/README.md +++ b/README.md @@ -1729,10 +1729,6 @@ to Elwetritsch. Since there is no compilation involved, copying disk images created in one machine to another machine should not incur in incompatibility problems. -Regarding dependencies for building DRAMSys and gem5, the scripts provided in -[DRAMSylva](DRAMSys/library/resources/scripts/DRAMSylva), when running on -Elwetritsch, will load the required modules automatically. - On gem5.TnT repository open a gem5.TnT config file. ```bash @@ -1764,19 +1760,34 @@ $ ./get_extra_fs.sh $ ./build_gem5.sh ``` -Example of a functional ~/.bashrc on Elwetritsch: +To get DRAMSys installed follow the traditional setup instructions described +in this document. + +For building DRAMSys one can profit from using +[DRAMSylva.sh](DRAMSys/library/resources/scripts/DRAMSylva/DRAMSylva.sh) which +loads the modules that are necessary for building DRAMSys on Elwetritsch. + +Regarding dependencies for building DRAMSys and DRAMSys + gem5, the scripts +provided in [DRAMSylva](DRAMSys/library/resources/scripts/DRAMSylva), when +running on Elwetritsch, will load the required modules automatically. + +As usual, one may export environment variables from his/her **~/.bashrc** file +on Elwetritch. Some segments extracted from a functional ~/.bashrc file are +presented below to be used as reference. Note that you may have to adapt it, +for example, changing paths to point to the place you installed some of the +libraries. ```bash # User specific aliases and functions # SystemC home -export SYSTEMC_HOME=$HOME/repos/systemc-2.3.1a +export SYSTEMC_HOME=$HOME/systemc-2.3.1a # SystemC target architecture export SYSTEMC_TARGET_ARCH=linux64 export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${SYSTEMC_HOME}/lib-linux64 # Qwt lib -export LIBQWT_HOME=$HOME/repos/qwt-6.1/lib -export LIBQWT_HEADERS=$HOME/repos/qwt-6.1/src +export LIBQWT_HOME=$HOME/qwt-6.1/lib +export LIBQWT_HEADERS=$HOME/qwt-6.1/src export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}$LIBQWT_HOME # Python lib From 84f0fc69e3c01c2120e8e373d1010587a3cd9175 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Tue, 29 Jan 2019 09:32:00 +0100 Subject: [PATCH 25/97] Submodule DRAMPower updated --- DRAMSys/library/src/common/third_party/DRAMPower | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DRAMSys/library/src/common/third_party/DRAMPower b/DRAMSys/library/src/common/third_party/DRAMPower index fa0627c4..746d56ea 160000 --- a/DRAMSys/library/src/common/third_party/DRAMPower +++ b/DRAMSys/library/src/common/third_party/DRAMPower @@ -1 +1 @@ -Subproject commit fa0627c4e6c5b35a040e416592061fb7e672daaf +Subproject commit 746d56ea53c5227428fff3e13716a68f259ad243 From c828ce41d1d79358173305a451683929dfe2742d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Fri, 8 Feb 2019 13:07:00 +0100 Subject: [PATCH 26/97] Coverage related flags added for DRAMSys_gem5 --- DRAMSys/gem5/gem5.pro | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/DRAMSys/gem5/gem5.pro b/DRAMSys/gem5/gem5.pro index e7ba799b..5b95e8b5 100644 --- a/DRAMSys/gem5/gem5.pro +++ b/DRAMSys/gem5/gem5.pro @@ -35,11 +35,15 @@ DEFINES += DRAMSYS_GEM5 unix:!macx { QMAKE_CXXFLAGS += -std=c++11 -O0 -g + QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage -fPIC -O0 + QMAKE_LFLAGS += -lgcov --coverage } macx: { CONFIG += c++11 QMAKE_CXXFLAGS += -std=c++0x -stdlib=libc++ -O0 -g + QMAKE_CXXFLAGS += --coverage + QMAKE_LFLAGS += --coverage } INCLUDEPATH += ../library/src/simulation/ From 218472fec99deb0ccf17ca0f620a5ef71fd5be87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Fri, 8 Feb 2019 13:47:59 +0100 Subject: [PATCH 27/97] New test for dramsys-gem5 (experimental) --- .gitlab-ci.yml | 3 +++ DRAMSys/tests/WIDEIO/ci.yml | 1 + DRAMSys/tests/dramsys-gem5/ci.yml | 32 +++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 DRAMSys/tests/dramsys-gem5/ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b9e0622e..aeca42b4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,3 +1,4 @@ +# vim: set ts=4 sw=4 expandtab: image: gcc variables: @@ -5,6 +6,7 @@ variables: stages: - build + - dramsys-gem5-build - WIDEIO - DDR3 - Coverage @@ -43,3 +45,4 @@ coverage: include: - '/DRAMSys/tests/DDR3/ci.yml' - '/DRAMSys/tests/WIDEIO/ci.yml' + - '/DRAMSys/tests/dramsys-gem5/ci.yml' diff --git a/DRAMSys/tests/WIDEIO/ci.yml b/DRAMSys/tests/WIDEIO/ci.yml index 7fc1ee7b..2b79cb5b 100644 --- a/DRAMSys/tests/WIDEIO/ci.yml +++ b/DRAMSys/tests/WIDEIO/ci.yml @@ -1,3 +1,4 @@ +# vim: set ts=4 sw=4 expandtab: example_wideio: stage: WIDEIO script: diff --git a/DRAMSys/tests/dramsys-gem5/ci.yml b/DRAMSys/tests/dramsys-gem5/ci.yml new file mode 100644 index 00000000..570be0e7 --- /dev/null +++ b/DRAMSys/tests/dramsys-gem5/ci.yml @@ -0,0 +1,32 @@ +# vim: set ts=4 sw=4 expandtab: +dramsys-gem5-build: + stage: dramsys-gem5-build + script: + - git submodule sync + - git submodule update --init --recursive + - cd DRAMSys/tests/dramsys-gem5 + - git clone https://github.com/tukl-msd/gem5.TnT.git + - cd gem5.TnT + - sudo ./dep_install.sh + - ./get_essential_repos.sh + - ./build_gem5.sh + - export GEM5=${HOME}/gem5_tnt/gem5 + - export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${GEM5}/build/ARM + - cd ../../.. + - rm -rf build + - mkdir -p build + - cd build + - qmake ../DRAMSys/DRAMSys.pro + - make -j$(cat /proc/cpuinfo | grep processor | wc -l) > build.log 2>&1 + cache: + key: build + paths: + - build/ + - DRAMSys/tests/dramsys-gem5/gem5.TnT + policy: push + + artifacts: + paths: + - build/build.log + expire_in: 2 days + From fe1257a55bde25a008da922feb6074c507d52b96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Fri, 8 Feb 2019 13:53:25 +0100 Subject: [PATCH 28/97] Typo fixed --- DRAMSys/tests/dramsys-gem5/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DRAMSys/tests/dramsys-gem5/ci.yml b/DRAMSys/tests/dramsys-gem5/ci.yml index 570be0e7..ab5aa1c7 100644 --- a/DRAMSys/tests/dramsys-gem5/ci.yml +++ b/DRAMSys/tests/dramsys-gem5/ci.yml @@ -12,7 +12,7 @@ dramsys-gem5-build: - ./build_gem5.sh - export GEM5=${HOME}/gem5_tnt/gem5 - export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${GEM5}/build/ARM - - cd ../../.. + - cd ../../../.. - rm -rf build - mkdir -p build - cd build From b0832944fda983c84173af5ab46675ab97585c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Fri, 8 Feb 2019 13:58:30 +0100 Subject: [PATCH 29/97] build folder exclusive for building dramsys + gem5 --- DRAMSys/tests/dramsys-gem5/ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/DRAMSys/tests/dramsys-gem5/ci.yml b/DRAMSys/tests/dramsys-gem5/ci.yml index ab5aa1c7..9c642473 100644 --- a/DRAMSys/tests/dramsys-gem5/ci.yml +++ b/DRAMSys/tests/dramsys-gem5/ci.yml @@ -13,20 +13,20 @@ dramsys-gem5-build: - export GEM5=${HOME}/gem5_tnt/gem5 - export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${GEM5}/build/ARM - cd ../../../.. - - rm -rf build - - mkdir -p build - - cd build + - rm -rf build-dramsys-gem5 + - mkdir -p build-dramsys-gem5 + - cd build-dramsys-gem5 - qmake ../DRAMSys/DRAMSys.pro - make -j$(cat /proc/cpuinfo | grep processor | wc -l) > build.log 2>&1 cache: key: build paths: - - build/ + - build-dramsys-gem5/ - DRAMSys/tests/dramsys-gem5/gem5.TnT policy: push artifacts: paths: - - build/build.log + - build-dramsys-gem5/build.log expire_in: 2 days From ed9650126ea7f369ec2c93d5d4c6a9f486004e3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Fri, 8 Feb 2019 14:00:59 +0100 Subject: [PATCH 30/97] Use of sudo is not appreciated by some tools --- DRAMSys/tests/dramsys-gem5/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/DRAMSys/tests/dramsys-gem5/ci.yml b/DRAMSys/tests/dramsys-gem5/ci.yml index 9c642473..e902b393 100644 --- a/DRAMSys/tests/dramsys-gem5/ci.yml +++ b/DRAMSys/tests/dramsys-gem5/ci.yml @@ -7,7 +7,6 @@ dramsys-gem5-build: - cd DRAMSys/tests/dramsys-gem5 - git clone https://github.com/tukl-msd/gem5.TnT.git - cd gem5.TnT - - sudo ./dep_install.sh - ./get_essential_repos.sh - ./build_gem5.sh - export GEM5=${HOME}/gem5_tnt/gem5 From 5cf34c8d5abde2f0bcd88b58e8870c736ca82f41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Fri, 8 Feb 2019 14:39:10 +0100 Subject: [PATCH 31/97] Allow failure until dependecies are properly installed on server --- DRAMSys/tests/dramsys-gem5/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/DRAMSys/tests/dramsys-gem5/ci.yml b/DRAMSys/tests/dramsys-gem5/ci.yml index e902b393..3e7e16f4 100644 --- a/DRAMSys/tests/dramsys-gem5/ci.yml +++ b/DRAMSys/tests/dramsys-gem5/ci.yml @@ -24,6 +24,10 @@ dramsys-gem5-build: - DRAMSys/tests/dramsys-gem5/gem5.TnT policy: push + # TODO: "allow_failure" should be removed as soon the server has + # dependencies properly installed + allow_failure: true + artifacts: paths: - build-dramsys-gem5/build.log From 4dc7b0478d866744219e9414ae38022c4a3258c0 Mon Sep 17 00:00:00 2001 From: Matthias Jung Date: Fri, 8 Feb 2019 15:39:09 +0100 Subject: [PATCH 32/97] just deactivated gem5 testing --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index aeca42b4..f4776ac5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -45,4 +45,4 @@ coverage: include: - '/DRAMSys/tests/DDR3/ci.yml' - '/DRAMSys/tests/WIDEIO/ci.yml' - - '/DRAMSys/tests/dramsys-gem5/ci.yml' + #- '/DRAMSys/tests/dramsys-gem5/ci.yml' # Should be activated again when a new gitlab runner with right dependencies is used From 75370b427af6f83c72c7cfbd6e1e11d9f8dba77b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Fri, 8 Feb 2019 19:21:52 +0100 Subject: [PATCH 33/97] Disable coverage with environment variable Default is ENABLED, export DRAMSYS_COVERAGE_CHECK_DISABLE=1 to disable it --- DRAMSys/DRAMSys.pro | 13 +++++++++++++ DRAMSys/gem5/gem5.pro | 27 ++++++++++++++++++++------- DRAMSys/library/library.pro | 27 ++++++++++++++++++++------- DRAMSys/simulator/simulator.pro | 27 ++++++++++++++++++++------- 4 files changed, 73 insertions(+), 21 deletions(-) diff --git a/DRAMSys/DRAMSys.pro b/DRAMSys/DRAMSys.pro index 3653e3bf..83be2a95 100644 --- a/DRAMSys/DRAMSys.pro +++ b/DRAMSys/DRAMSys.pro @@ -11,6 +11,19 @@ $$eval(thermalsim) { message(Thermal Simulation Feature Disabled) } +dramsys_disable_coverage_check = $$(DRAMSYS_DISABLE_COVERAGE_CHECK) +isEmpty(dramsys_disable_coverage_check) { + message(Coverage check ENABLED) +} else { + message(Coverage check DISABLED) +} + +systemc_home = $$(SYSTEMC_HOME) +isEmpty(systemc_home) { + systemc_home = /opt/systemc +} +message(SystemC home is $${systemc_home}) + SUBDIRS += library SUBDIRS += simulator SUBDIRS += traceAnalyzer diff --git a/DRAMSys/gem5/gem5.pro b/DRAMSys/gem5/gem5.pro index 5b95e8b5..122bb1b0 100644 --- a/DRAMSys/gem5/gem5.pro +++ b/DRAMSys/gem5/gem5.pro @@ -33,17 +33,30 @@ DEFINES += TIXML_USE_STL DEFINES += SC_INCLUDE_DYNAMIC_PROCESSES DEFINES += DRAMSYS_GEM5 +dramsys_disable_coverage_check = $$(DRAMSYS_DISABLE_COVERAGE_CHECK) +isEmpty(dramsys_disable_coverage_check) { + coverage_check = true + message(Coverage check ENABLED) +} else { + coverage_check = false + message(Coverage check DISABLED) +} + unix:!macx { - QMAKE_CXXFLAGS += -std=c++11 -O0 -g - QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage -fPIC -O0 - QMAKE_LFLAGS += -lgcov --coverage + QMAKE_CXXFLAGS += -std=c++11 -O0 -g + $$eval(coverage_check) { + QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage -fPIC -O0 + QMAKE_LFLAGS += -lgcov --coverage + } } macx: { - CONFIG += c++11 - QMAKE_CXXFLAGS += -std=c++0x -stdlib=libc++ -O0 -g - QMAKE_CXXFLAGS += --coverage - QMAKE_LFLAGS += --coverage + CONFIG += c++11 + QMAKE_CXXFLAGS += -std=c++0x -stdlib=libc++ -O0 -g + $$eval(coverage_check) { + QMAKE_CXXFLAGS += --coverage + QMAKE_LFLAGS += --coverage + } } INCLUDEPATH += ../library/src/simulation/ diff --git a/DRAMSys/library/library.pro b/DRAMSys/library/library.pro index 58d3037b..113fe07d 100644 --- a/DRAMSys/library/library.pro +++ b/DRAMSys/library/library.pro @@ -56,17 +56,30 @@ INCLUDEPATH += src/common/third_party/json/include DEFINES += TIXML_USE_STL DEFINES += SC_INCLUDE_DYNAMIC_PROCESSES +dramsys_disable_coverage_check = $$(DRAMSYS_DISABLE_COVERAGE_CHECK) +isEmpty(dramsys_disable_coverage_check) { + coverage_check = true + message(Coverage check ENABLED) +} else { + coverage_check = false + message(Coverage check DISABLED) +} + unix:!macx { - QMAKE_CXXFLAGS += -std=c++11 -O0 -g - QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage -fPIC -O0 - QMAKE_LFLAGS += -lgcov --coverage + QMAKE_CXXFLAGS += -std=c++11 -O0 -g + $$eval(coverage_check) { + QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage -fPIC -O0 + QMAKE_LFLAGS += -lgcov --coverage + } } macx: { - CONFIG += c++11 - QMAKE_CXXFLAGS += -std=c++0x -stdlib=libc++ -O0 -g - QMAKE_CXXFLAGS += --coverage - QMAKE_LFLAGS += --coverage + CONFIG += c++11 + QMAKE_CXXFLAGS += -std=c++0x -stdlib=libc++ -O0 -g + $$eval(coverage_check) { + QMAKE_CXXFLAGS += --coverage + QMAKE_LFLAGS += --coverage + } } QMAKE_CXXFLAGS += -isystem $${systemc_home}/include diff --git a/DRAMSys/simulator/simulator.pro b/DRAMSys/simulator/simulator.pro index dd592f3d..f9439be1 100644 --- a/DRAMSys/simulator/simulator.pro +++ b/DRAMSys/simulator/simulator.pro @@ -18,6 +18,15 @@ isEmpty(systemc_target_arch) { message(SystemC target architecture is $${systemc_target_arch}) +dramsys_disable_coverage_check = $$(DRAMSYS_DISABLE_COVERAGE_CHECK) +isEmpty(dramsys_disable_coverage_check) { + coverage_check = true + message(Coverage check ENABLED) +} else { + coverage_check = false + message(Coverage check DISABLED) +} + unix:!macx { message(Building on a GNU/Linux) QMAKE_RPATHDIR += $${systemc_home}/lib-$${systemc_target_arch} @@ -28,16 +37,20 @@ DEFINES += TIXML_USE_STL DEFINES += SC_INCLUDE_DYNAMIC_PROCESSES unix:!macx { - QMAKE_CXXFLAGS += -std=c++11 -O0 -g - QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage -fPIC -O0 - QMAKE_LFLAGS += -lgcov --coverage + QMAKE_CXXFLAGS += -std=c++11 -O0 -g + $$eval(coverage_check) { + QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage -fPIC -O0 + QMAKE_LFLAGS += -lgcov --coverage + } } macx: { - CONFIG += c++11 - QMAKE_CXXFLAGS += -std=c++0x -stdlib=libc++ -O0 -g - QMAKE_CXXFLAGS += --coverage - QMAKE_LFLAGS += --coverage + CONFIG += c++11 + QMAKE_CXXFLAGS += -std=c++0x -stdlib=libc++ -O0 -g + $$eval(coverage_check) { + QMAKE_CXXFLAGS += --coverage + QMAKE_LFLAGS += --coverage + } } INCLUDEPATH += ../library/src/simulation/ From 05ab72146a195beb10590d5127ee9aa06c2d2cd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Tue, 12 Feb 2019 15:12:29 +0100 Subject: [PATCH 34/97] Project's extra files list updated --- DRAMSys/gem5/gem5.pro | 71 +++++++++++++++++++++---- DRAMSys/library/resources/resources.pri | 33 ++++++++++-- 2 files changed, 91 insertions(+), 13 deletions(-) diff --git a/DRAMSys/gem5/gem5.pro b/DRAMSys/gem5/gem5.pro index 122bb1b0..031a3e86 100644 --- a/DRAMSys/gem5/gem5.pro +++ b/DRAMSys/gem5/gem5.pro @@ -92,23 +92,76 @@ SOURCES += $${gem5_root}/util/tlm/src/sim_control.cc SOURCES += main.cpp DISTFILES += ../DRAMSys.astylerc -DISTFILES += configs/singleElasticTraceReplay.ini + +DISTFILES += etrace_single/config.ini +DISTFILES += etrace_single_L2/HPCG-47MB/config.ini +DISTFILES += etrace_single_L2/Pathfinder/config.ini +DISTFILES += etrace_single_L2/hpcc-linpack/config.ini +DISTFILES += etrace_single_L2/hpcc-fft/config.ini +DISTFILES += etrace_single_L2/config.ini +DISTFILES += etrace_single_L2/hpcc-dgemm/config.ini +DISTFILES += etrace_single_L2/hpcc-gups/config.ini DISTFILES += configs/singleElasticTraceReplayWithL2.ini -DISTFILES += configs/dualElasticTraceReplay.ini DISTFILES += configs/nvdimmp.ini DISTFILES += configs/hello.ini +DISTFILES += configs/dualElasticTraceReplay.ini +DISTFILES += configs/singleElasticTraceReplay.ini DISTFILES += configs/boot_linux.ini +DISTFILES += gem5_fs/stream/config.ini +DISTFILES += gem5_fs/stream/stream_1_cores.rcS +DISTFILES += gem5_fs/parsec/simmedium/fluidanimate/fluidanimate_simmedium_2.rcS +DISTFILES += gem5_fs/parsec/simmedium/fluidanimate/config.ini +DISTFILES += gem5_fs/parsec/simmedium/ferret/config.ini +DISTFILES += gem5_fs/parsec/simmedium/ferret/ferret_simmedium_2.rcS +DISTFILES += gem5_fs/parsec/simmedium/blackscholes/blackscholes_simmedium_2.rcS +DISTFILES += gem5_fs/parsec/simmedium/blackscholes/config.ini +DISTFILES += gem5_fs/parsec/simlarge/streamcluster/config.ini +DISTFILES += gem5_fs/parsec/simlarge/streamcluster/streamcluster_simlarge_2.rcS +DISTFILES += gem5_fs/parsec/simsmall/fluidanimate/fluidanimate_simsmall_2.rcS +DISTFILES += gem5_fs/parsec/simsmall/fluidanimate/config.ini +DISTFILES += gem5_fs/parsec/simsmall/bodytrack/bodytrack_simsmall_2.rcS +DISTFILES += gem5_fs/parsec/simsmall/bodytrack/config.ini +DISTFILES += gem5_fs/parsec/simsmall/ferret/config.ini +DISTFILES += gem5_fs/parsec/simsmall/ferret/ferret_simsmall_2.rcS +DISTFILES += gem5_fs/parsec/simsmall/blackscholes/config.ini +DISTFILES += gem5_fs/parsec/simsmall/blackscholes/blackscholes_simsmall_2.rcS +DISTFILES += gem5_fs/parsec/simdev/fluidanimate/config.ini +DISTFILES += gem5_fs/parsec/simdev/fluidanimate/fluidanimate_simdev_2.rcS +DISTFILES += gem5_fs/parsec/simdev/blackscholes/blackscholes_simdev_2.rcS +DISTFILES += gem5_fs/parsec/simdev/blackscholes/config.ini DISTFILES += examples/tlm_elastic_slave.py DISTFILES += examples/tlm_elastic_slave_mc_direct.py DISTFILES += examples/tlm_elastic_slave_with_l2.py +DISTFILES += gem5_se/almabench/config.ini +DISTFILES += gem5_se/fldry/config.ini +DISTFILES += gem5_se/Queens/config.ini +DISTFILES += gem5_se/chomp/config.ini +DISTFILES += gem5_se/l1_cache/Queens/config.ini +DISTFILES += gem5_se/l1_cache/chomp/config.ini +DISTFILES += gem5_se/l1_cache/Puzzle/config.ini +DISTFILES += gem5_se/l1_cache/RealMM/config.ini +DISTFILES += gem5_se/l1_cache/Perm/config.ini +DISTFILES += gem5_se/l1_cache/Treesort/config.ini +DISTFILES += gem5_se/l1_cache/Bubblesort/config.ini +DISTFILES += gem5_se/l1_cache/misr/config.ini +DISTFILES += gem5_se/l1_cache/exptree/config.ini +DISTFILES += gem5_se/l1_cache/Quicksort/config.ini +DISTFILES += gem5_se/l1_cache/IntMM/config.ini +DISTFILES += gem5_se/l1_cache/Oscar/config.ini +DISTFILES += gem5_se/l1_cache/FloatMM/config.ini +DISTFILES += gem5_se/l1_cache/Towers/config.ini +DISTFILES += gem5_se/run.sh +DISTFILES += gem5_se/Puzzle/config.ini +DISTFILES += gem5_se/RealMM/config.ini +DISTFILES += gem5_se/Perm/config.ini +DISTFILES += gem5_se/Treesort/config.ini DISTFILES += gem5_se/Bubblesort/config.ini +DISTFILES += gem5_se/misr/config.ini +DISTFILES += gem5_se/lpbench/config.ini +DISTFILES += gem5_se/8_cores/config.ini +DISTFILES += gem5_se/exptree/config.ini +DISTFILES += gem5_se/Quicksort/config.ini DISTFILES += gem5_se/IntMM/config.ini DISTFILES += gem5_se/Oscar/config.ini -DISTFILES += gem5_se/Perm/config.ini -DISTFILES += gem5_se/Puzzle/config.ini -DISTFILES += gem5_se/Queens/config.ini -DISTFILES += gem5_se/Quicksort/config.ini -DISTFILES += gem5_se/RealMM/config.ini +DISTFILES += gem5_se/FloatMM/config.ini DISTFILES += gem5_se/Towers/config.ini -DISTFILES += gem5_se/Treesort/config.ini -DISTFILES += gem5_se/run.sh diff --git a/DRAMSys/library/resources/resources.pri b/DRAMSys/library/resources/resources.pri index 36bf4859..ddd5d42b 100644 --- a/DRAMSys/library/resources/resources.pri +++ b/DRAMSys/library/resources/resources.pri @@ -77,16 +77,41 @@ DISTFILES += resources/scripts/analyse_trace.pl DISTFILES += resources/scripts/video_rendering/temperatur.job.pl DISTFILES += resources/scripts/video_rendering/temperatur.pl DISTFILES += resources/scripts/video_rendering/Makefile -DISTFILES += resources/scripts/DRAMSylva/LICENSE -DISTFILES += resources/scripts/DRAMSylva/README -DISTFILES += resources/scripts/DRAMSylva/DRAMSylva.patch +DISTFILES += resources/scripts/DRAMSylva/collect.sh +DISTFILES += resources/scripts/DRAMSylva/common.in +DISTFILES += resources/scripts/DRAMSylva/DRAMSylva.jobscript DISTFILES += resources/scripts/DRAMSylva/DRAMSylva.sh DISTFILES += resources/scripts/DRAMSylva/DRAMSylvaCSVPlot.py DISTFILES += resources/scripts/DRAMSylva/DRAMSyrup.py -DISTFILES += resources/scripts/DRAMSylva/configs.json +DISTFILES += resources/scripts/DRAMSylva/gem5ilva.jobscript +DISTFILES += resources/scripts/DRAMSylva/gem5ilva.sh +DISTFILES += resources/scripts/DRAMSylva/gem5ilva_fs.jobscript +DISTFILES += resources/scripts/DRAMSylva/gem5ilva_fs.sh +DISTFILES += resources/scripts/DRAMSylva/LICENSE +DISTFILES += resources/scripts/DRAMSylva/README +DISTFILES += resources/scripts/DRAMSylva/configs_json/configs.json +DISTFILES += resources/scripts/DRAMSylva/configs_json/configsbrc.json +DISTFILES += resources/scripts/DRAMSylva/configs_json/configsbrc1x.json +DISTFILES += resources/scripts/DRAMSylva/configs_json/configsbrc1x_gem5.json +DISTFILES += resources/scripts/DRAMSylva/configs_json/configsbrc2x.json +DISTFILES += resources/scripts/DRAMSylva/configs_json/configsbrc2x_gem5.json +DISTFILES += resources/scripts/DRAMSylva/configs_json/configsbrc4x.json +DISTFILES += resources/scripts/DRAMSylva/configs_json/configsbrc4x_gem5.json +DISTFILES += resources/scripts/DRAMSylva/configs_json/configsrbc.json +DISTFILES += resources/scripts/DRAMSylva/configs_json/configsrbc1x.json +DISTFILES += resources/scripts/DRAMSylva/configs_json/configsrbc1x_gem5.json +DISTFILES += resources/scripts/DRAMSylva/configs_json/configsrbc1x_gem5_fs.json +DISTFILES += resources/scripts/DRAMSylva/configs_json/configsrbc1x_gem5_fs_nodb.json +DISTFILES += resources/scripts/DRAMSylva/configs_json/configsrbc2x.json +DISTFILES += resources/scripts/DRAMSylva/configs_json/configsrbc2x_gem5.json +DISTFILES += resources/scripts/DRAMSylva/configs_json/configsrbc4x.json +DISTFILES += resources/scripts/DRAMSylva/configs_json/configsrbc4x_gem5.json +DISTFILES += resources/scripts/DRAMSylva/configs_json/ref.json +DISTFILES += resources/scripts/DRAMSylva/configs_json/ref_bw.json DISTFILES += resources/scripts/trace_gen.py DISTFILES += resources/scripts/traceGenerationForNNTraining.pl + # Trace Files DISTFILES += resources/traces/chstone-aes_32.stl DISTFILES += resources/traces/test2.stl From bf8bed0dcbd52d1687a7c7e9dd4222777644a0e1 Mon Sep 17 00:00:00 2001 From: "Felipe S. Prado" Date: Thu, 14 Feb 2019 18:01:38 +0100 Subject: [PATCH 35/97] Delete playersTlmCheckers at the end of the simulation --- DRAMSys/library/src/simulation/DRAMSys.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/DRAMSys/library/src/simulation/DRAMSys.cpp b/DRAMSys/library/src/simulation/DRAMSys.cpp index 92c47141..3e2bc6ea 100644 --- a/DRAMSys/library/src/simulation/DRAMSys.cpp +++ b/DRAMSys/library/src/simulation/DRAMSys.cpp @@ -314,6 +314,10 @@ DRAMSys::~DRAMSys() delete rec; } + for (auto tlmChecker : playersTlmCheckers) { + delete tlmChecker; + } + for (auto tlmChecker : controllersTlmCheckers) { delete tlmChecker; } From a70fd4f48a4c94e59d4f788ad4a14e00b5a06987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Fri, 15 Feb 2019 11:31:12 +0100 Subject: [PATCH 36/97] Doc updated More info on how to run gem5ilva and gem5ilva_fs scripts --- README.md | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3fe92431..e43fcef3 100644 --- a/README.md +++ b/README.md @@ -1704,12 +1704,40 @@ If you need help please contact Matthias Jung. ### DRAMSys + GEM5 Log Collector Script -Users can profit of running multiple simulations automatically with -[gem5ilva](DRAMSys/library/resources/scripts/DRAMSylva/gem5ilva.sh). +Users can profit of running multiple **DRAMSys + gem5 simulations** +automatically with +[gem5ilva](DRAMSys/library/resources/scripts/DRAMSylva/gem5ilva.sh) for **gem5 +syscall emulation (SE) mode** and +[gem5ilva_fs](DRAMSys/library/resources/scripts/DRAMSylva/gem5ilva.sh) for +**gem5 full system (FS) mode**. + +Normally you will have to push your changes before running the scripts. This +approach makes it easier to track back what exactly was tested by the scripts. + +In the scripts there are variables to tell **git** where to get the source +code from, user name, **branch**, etc. The variable are: + +```bash +# Git info. +git_user="$USER" +git_branch="master" +git_url="git.eit.uni-kl.de:ems/astdm/dram.sys.git" +git_url_https="git.eit.uni-kl.de/ems/astdm/dram.sys.git" +``` + +Nevertheless, for some cases, you may want to have gem5 files out of the main +repository (usually because they are too big to be added to the repository). + +For those cases uncomment and properly set the variable +**external_inifile_path** in +[gem5ilva_fs](DRAMSys/library/resources/scripts/DRAMSylva/gem5ilva.sh). + +This will allow you to use a gem5 **config.ini** file external to the +repository. Note, however, that in this case it is up to you to keep track of +your simulation files. ### Notes for [Elwetritsch](https://elwe.rhrk.uni-kl.de/) Users - Firstly, take a look at [High Performance Computing at the TU Kaiserslautern](https://elwe.rhrk.uni-kl.de/). From 4604f83be7a89e702bf5eef6ef94756e6bc40963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Fri, 15 Feb 2019 12:06:15 +0100 Subject: [PATCH 37/97] Doc improved --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e43fcef3..da0d55b7 100644 --- a/README.md +++ b/README.md @@ -1708,14 +1708,15 @@ Users can profit of running multiple **DRAMSys + gem5 simulations** automatically with [gem5ilva](DRAMSys/library/resources/scripts/DRAMSylva/gem5ilva.sh) for **gem5 syscall emulation (SE) mode** and -[gem5ilva_fs](DRAMSys/library/resources/scripts/DRAMSylva/gem5ilva.sh) for +[gem5ilva_fs](DRAMSys/library/resources/scripts/DRAMSylva/gem5ilva_fs.sh) for **gem5 full system (FS) mode**. Normally you will have to push your changes before running the scripts. This approach makes it easier to track back what exactly was tested by the scripts. In the scripts there are variables to tell **git** where to get the source -code from, user name, **branch**, etc. The variable are: +code from (the repository URL), user name to be used by git (from your git +account), **branch** (your working branch), etc. The variable are: ```bash # Git info. @@ -1725,6 +1726,9 @@ git_url="git.eit.uni-kl.de:ems/astdm/dram.sys.git" git_url_https="git.eit.uni-kl.de/ems/astdm/dram.sys.git" ``` +Open the script in QtCreator or another text editor of your choice and set the +variables with values that fit your needs. + Nevertheless, for some cases, you may want to have gem5 files out of the main repository (usually because they are too big to be added to the repository). @@ -1736,6 +1740,10 @@ This will allow you to use a gem5 **config.ini** file external to the repository. Note, however, that in this case it is up to you to keep track of your simulation files. +**Hint:** +[gem5.TnT](https://github.com/tukl-msd/gem5.TnT) provides convenience scripts +to create gem5 disk images with benchmarking programs embedded. + ### Notes for [Elwetritsch](https://elwe.rhrk.uni-kl.de/) Users Firstly, take a look at [High Performance Computing at the TU From 51f1a44a5d6623a9fce73b9c8eb08f932db0365c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Fri, 15 Feb 2019 12:17:08 +0100 Subject: [PATCH 38/97] Doc - links fixed, text improved --- README.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index da0d55b7..dc9a3ea3 100644 --- a/README.md +++ b/README.md @@ -1702,7 +1702,7 @@ An overview of the architcture being simulated is presented below: For more spophisticated setups, even with l2 caches the proper ini file should be created. If you need help please contact Matthias Jung. -### DRAMSys + GEM5 Log Collector Script +### DRAMSys + GEM5 Log Collector Scripts Users can profit of running multiple **DRAMSys + gem5 simulations** automatically with @@ -1714,9 +1714,9 @@ syscall emulation (SE) mode** and Normally you will have to push your changes before running the scripts. This approach makes it easier to track back what exactly was tested by the scripts. -In the scripts there are variables to tell **git** where to get the source -code from (the repository URL), user name to be used by git (from your git -account), **branch** (your working branch), etc. The variable are: +The scripts provide variables that tell **git** where to get the source +code from (repository URL), user name to be used (your git account), +**branch** to checkout (your working branch), etc. They are: ```bash # Git info. @@ -1729,16 +1729,17 @@ git_url_https="git.eit.uni-kl.de/ems/astdm/dram.sys.git" Open the script in QtCreator or another text editor of your choice and set the variables with values that fit your needs. -Nevertheless, for some cases, you may want to have gem5 files out of the main -repository (usually because they are too big to be added to the repository). +Nevertheless, for some cases, you may want to have gem5 essential files out of +the main repository (usually because they are too big to be added to the +repository). For those cases uncomment and properly set the variable **external_inifile_path** in -[gem5ilva_fs](DRAMSys/library/resources/scripts/DRAMSylva/gem5ilva.sh). +[gem5ilva_fs](DRAMSys/library/resources/scripts/DRAMSylva/gem5ilva_fs.sh). -This will allow you to use a gem5 **config.ini** file external to the -repository. Note, however, that in this case it is up to you to keep track of -your simulation files. +This allows you to use a gem5 **config.ini** file external to the repository. +Note, however, that in this case it is up to you to keep track of your +simulation setup. **Hint:** [gem5.TnT](https://github.com/tukl-msd/gem5.TnT) provides convenience scripts From f2520db93b1dd4cdf8053e8d327f5c4d36521ba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Sun, 17 Feb 2019 18:17:12 +0100 Subject: [PATCH 39/97] Doc improved --- README.md | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index dc9a3ea3..b4b8e49e 100644 --- a/README.md +++ b/README.md @@ -1704,11 +1704,11 @@ If you need help please contact Matthias Jung. ### DRAMSys + GEM5 Log Collector Scripts -Users can profit of running multiple **DRAMSys + gem5 simulations** +Users can profit of running multiple **DRAMSys + gem5** simulations automatically with -[gem5ilva](DRAMSys/library/resources/scripts/DRAMSylva/gem5ilva.sh) for **gem5 +[gem5ilva.sh](DRAMSys/library/resources/scripts/DRAMSylva/gem5ilva.sh) for **gem5 syscall emulation (SE) mode** and -[gem5ilva_fs](DRAMSys/library/resources/scripts/DRAMSylva/gem5ilva_fs.sh) for +[gem5ilva_fs.sh](DRAMSys/library/resources/scripts/DRAMSylva/gem5ilva_fs.sh) for **gem5 full system (FS) mode**. Normally you will have to push your changes before running the scripts. This @@ -1726,6 +1726,13 @@ git_url="git.eit.uni-kl.de:ems/astdm/dram.sys.git" git_url_https="git.eit.uni-kl.de/ems/astdm/dram.sys.git" ``` +The default values of the variables presented above assume that your git +account uses the same name as your user name in your PC. If that is not the +case, replace the value of the **git_user** variable with your git account +name. Similarly, replace the value of the variable **git_branch** with your +working branch name. There (in your working branch) you can push your changes +and/or new files before executing the scripts. + Open the script in QtCreator or another text editor of your choice and set the variables with values that fit your needs. @@ -1735,7 +1742,7 @@ repository). For those cases uncomment and properly set the variable **external_inifile_path** in -[gem5ilva_fs](DRAMSys/library/resources/scripts/DRAMSylva/gem5ilva_fs.sh). +[gem5ilva_fs.sh](DRAMSys/library/resources/scripts/DRAMSylva/gem5ilva_fs.sh). This allows you to use a gem5 **config.ini** file external to the repository. Note, however, that in this case it is up to you to keep track of your @@ -1805,8 +1812,9 @@ For building DRAMSys one can profit from using loads the modules that are necessary for building DRAMSys on Elwetritsch. Regarding dependencies for building DRAMSys and DRAMSys + gem5, the scripts -provided in [DRAMSylva](DRAMSys/library/resources/scripts/DRAMSylva), when -running on Elwetritsch, will load the required modules automatically. +provided inside the [DRAMSylva +folder](DRAMSys/library/resources/scripts/DRAMSylva), when running on +Elwetritsch, will load the required modules automatically. As usual, one may export environment variables from his/her **~/.bashrc** file on Elwetritch. Some segments extracted from a functional ~/.bashrc file are From 3b98741605b9c7e0fdb98ef92b60d3ae5bcb0953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Mon, 18 Feb 2019 11:07:08 +0100 Subject: [PATCH 40/97] Doc improved --- README.md | 73 +++++++++++++++++++++++++++++++++++-------------- utils/getqwt.sh | 10 +++---- 2 files changed, 57 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index b4b8e49e..10183c27 100644 --- a/README.md +++ b/README.md @@ -28,10 +28,9 @@ $ git config --global color.ui auto ``` Now clone the repository into a local folder on your computer. -Replace the occurrences of the word **user** with your own user name. ```bash -$ git clone --recursive https://user@git.eit.uni-kl.de:ems/astdm/dram.sys.git +$ git clone --recursive https://git.eit.uni-kl.de/ems/astdm/dram.sys.git ``` The *--recursive* flag tells git to initialize all submodules within the @@ -43,7 +42,7 @@ Now you can implement, test, commit and push features into a **branch**. When you consider your work stable enough to be merged into the master branch it is time to open a **merge request** using the web interface. -Your changes will be reviewed and finally integrated to the master branch. +Your changes will be reviewed and finally integrated into the master branch. After cloning go to the project directory. @@ -53,26 +52,34 @@ $ cd dram.sys ### Dependencies -Make sure you have properly installed in your system the required libraries -and programs. +Make sure you have properly installed all the required libraries and +tools in your system. - **General dependencies** -You can use [utils/install_deb.sh](./utils/install_deb.sh) in order to install dependencies. First -read and understand the script then execute it. Type your password if -required. +You may want to have a look on the convenience scripts that are located in the +[utils](./utils) folder. ```bash -$ bash install_deb.sh +$ cd utils +$ ls ``` -- **SystemC 2.3.1 and TLM 2.0** - -You can use [utils/getsysc.sh](./utils/getsysc.sh) to download and install SystemC 2.3.1 -and TLM 2.0. First read and understand the script then execute it. +You can use [utils/install_deb.sh](./utils/install_deb.sh) in order to install +dependencies. First read and understand the script, then execute it. Type your +password if required. ```bash -$ bash getsysc.sh +$ ./install_deb.sh +``` + +- **SystemC 2.3.1a and TLM-2.0** + +You can use [utils/getsysc.sh](./utils/getsysc.sh) to download and install SystemC 2.3.1a +and TLM-2.0. First read and understand the script then execute it. + +```bash +$ ./getsysc.sh ``` Alternatively, the sources can be downloaded from @@ -85,9 +92,24 @@ You can use [utils/getqwt.sh](./utils/getqwt.sh) in order to install qwt-6.1. Fi and understand the script then execute it. ```bash -$ bash getqwt.sh +$ ./getqwt.sh $ cd ~/qwt-6.1 -$ sudo make install +``` + +After that add environment variables to your ~/.bashrc. + +```bash +export LIBQWT_HOME=${HOME}/qwt-6.1/lib +export LIBQWT_HEADERS=${HOME}/qwt-6.1/src +export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}${LIBQWT_HOME} +``` + +Remember to verify that the library and header files are located in paths you +specify. You can use the **ls** command to accomplish that. + +```bash +$ ls ${HOME}/qwt-6.1/lib +$ ls ${HOME}/qwt-6.1/src ``` Further information about Qwt can be found [here](http://qwt.sourceforge.net/). @@ -104,17 +126,17 @@ environment variables accordingly**. # SystemC home and target architecture export SYSTEMC_HOME=$HOME/systemc-2.3.1a export SYSTEMC_TARGET_ARCH=linux64 +export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${SYSTEMC_HOME}/lib-$SYSTEMC_TARGET_ARCH # DRAMSys libraries and headers export LIBPYTHON_VERSION="3.5m" export PYTHON_HOME=/usr/lib/python3.5 export PYTHON_HEADERS=/usr/include/python3.5m -export LIBQWT_HOME=/usr/local/qwt-6.1.4-svn/lib -export LIBQWT_HEADERS=/usr/local/qwt-6.1.4-svn/include +export LIBQWT_HOME=${HOME}/qwt-6.1/lib +export LIBQWT_HEADERS=${HOME}/qwt-6.1/src +export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}${LIBQWT_HOME} -export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}$LIBQWT_HOME -export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${SYSTEMC_HOME}/lib-$SYSTEMC_TARGET_ARCH ``` ### Coding Style @@ -1828,7 +1850,6 @@ libraries. export SYSTEMC_HOME=$HOME/systemc-2.3.1a # SystemC target architecture export SYSTEMC_TARGET_ARCH=linux64 -export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${SYSTEMC_HOME}/lib-linux64 # Qwt lib export LIBQWT_HOME=$HOME/qwt-6.1/lib @@ -1862,6 +1883,16 @@ using nodes of the Elwetritsch cluster. Of course, one can create his/her own job scripts. +### Coverage Check + +Coverage check is enabled by default and can be disabled with an environment +variable. + +```bash +export DRAMSYS_DISABLE_COVERAGE_CHECK=1 +``` + + ## References [1] TLM Modelling of 3D Stacked Wide I/O DRAM Subsystems, A Virtual Platform for Memory Controller Design Space Exploration diff --git a/utils/getqwt.sh b/utils/getqwt.sh index d197a1da..7b78ff71 100755 --- a/utils/getqwt.sh +++ b/utils/getqwt.sh @@ -35,11 +35,11 @@ dest=$HOME/qwt-6.1 svn checkout svn://svn.code.sf.net/p/qwt/code/branches/qwt-6.1 $dest cd $dest +if [[ $(hostname -s) =~ ^head[0-9]+$ ]] || [[ $(hostname -s) =~ ^node[0-9]+$ ]]; then + # Elwetritsch cluster - heads or nodes + module load qt/5.5 +else qmake qwt.pro svn up -r 2481 make - -# Add env. variables to ~/.bashrc -echo "export LIBQWT_HOME=/usr/local/qwt-6.1.4-svn/lib" >> ~/.bashrc -echo "export LIBQWT_HEADERS=/usr/local/qwt-6.1.4-svn/include" >> ~/.bashrc -echo "Now go to $dest and execute \"sudo make install\"." +echo "Done." From 3ed1d81b743f9c7e471554bff652e251f791dcde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Mon, 18 Feb 2019 13:41:01 +0100 Subject: [PATCH 41/97] Convenience script fixed --- utils/getqwt.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/getqwt.sh b/utils/getqwt.sh index 7b78ff71..82cb80d2 100755 --- a/utils/getqwt.sh +++ b/utils/getqwt.sh @@ -35,11 +35,11 @@ dest=$HOME/qwt-6.1 svn checkout svn://svn.code.sf.net/p/qwt/code/branches/qwt-6.1 $dest cd $dest +svn up -r 2481 if [[ $(hostname -s) =~ ^head[0-9]+$ ]] || [[ $(hostname -s) =~ ^node[0-9]+$ ]]; then # Elwetritsch cluster - heads or nodes module load qt/5.5 else qmake qwt.pro -svn up -r 2481 make echo "Done." From e1446a0646826356ac04254c05cf6c1a0b3f1323 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Mon, 18 Feb 2019 13:56:35 +0100 Subject: [PATCH 42/97] Typo fixed --- utils/getqwt.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/getqwt.sh b/utils/getqwt.sh index 82cb80d2..b3f43208 100755 --- a/utils/getqwt.sh +++ b/utils/getqwt.sh @@ -39,7 +39,7 @@ svn up -r 2481 if [[ $(hostname -s) =~ ^head[0-9]+$ ]] || [[ $(hostname -s) =~ ^node[0-9]+$ ]]; then # Elwetritsch cluster - heads or nodes module load qt/5.5 -else +fi qmake qwt.pro make echo "Done." From 147e3a2565ab553f13a51494cabde392318850ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Wed, 20 Feb 2019 16:56:52 +0100 Subject: [PATCH 43/97] Doc improved --- README.md | 81 +++++++++++++++++++++++++++---------------------------- 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 10183c27..8ca1e149 100644 --- a/README.md +++ b/README.md @@ -966,7 +966,7 @@ A description of the content each directory follows. ### Log Collector Script Users can profit of running multiple simulations automatically with -[DRAMSylva](DRAMSys/library/resources/scripts/DRAMSylva/DRAMSylva.sh). +[DRAMSylva.sh]. Every time you run the script you get a new folder with the name containing the execution time: dram.sys\_YYYY\_MM\_DD-HH.MM.SS. @@ -1066,8 +1066,9 @@ If some traces in trace_list are compressed in a tar.gz and require decompression before execution the option **tgz_traces** can be set to **yes**. The tarball is specified by the variable **tgz_file** and it is expected to be available (already commited and pushed to be available after -cloning) in the [trace folder](DRAMSys/library/resources/traces). DRAMSylva -will uncompress the tarball extracting the traces before using them. +cloning) in the [trace folder](DRAMSys/library/resources/traces). +[DRAMSylva.sh] will uncompress the tarball extracting the traces before using +them. ```bash tgz_traces="yes" @@ -1078,16 +1079,15 @@ Set the variable **use_json_cfg** to **yes** in order to override sim_files with new simulation files generated from a JSON description. Otherwise the simulation files are the ones specified by sim_files. Files are expected to be available (already commited and pushed to be available after cloning) in -[configs_json](DRAMSys/library/resources/scripts/DRAMSylva/configs_json). +[configs_json]. ```bash use_json_cfg="yes" ``` All the essential simuation files are auto generated accordingly to each of -the JSON descriptions provided in **json_cfg_list**. -Several examples of JSON configuration files are provided in -[configs_json](DRAMSys/library/resources/scripts/DRAMSylva/configs_json). +the JSON descriptions provided in **json_cfg_list**. Several examples of JSON +configuration files are provided in [configs_json]. + Insert the desired simulation data in one or multiple JSON files following any of the examples provided, e.g., @@ -1095,7 +1095,7 @@ Several examples of JSON configuration files are provided in Multiple arrays are allowed and encouraged. Each array corresponds to a full simulation setup. -+ Add your JSON files to **json_cfg_list** in DRAMSylva.sh. ++ Add your JSON files to **json_cfg_list** in [DRAMSylva.sh]. ```bash json_cfg_list=" @@ -1106,11 +1106,11 @@ ref_bw.json + Commit and push your changes. -+ Run **DRAMSylva** as previously described. All generated files will be ++ Run **[DRAMSylva.sh]** as previously described. All generated files will be inside the output folder, so it will be possible to keep a perfect track of all simulations. -For more information check the documentation in [DRAMSylva](DRAMSys/library/resources/scripts/DRAMSylva). +For more information check the documentation inside [DRAMSylva folder]. ### Trace Generator Script @@ -1438,7 +1438,7 @@ $ ./DRAMSys > output ## DRAMSys with gem5 Install gem5 by following the instructions on the [gem5 wiki](http://gem5.org/Documentation#Getting_Started). -Optionally, use the scripts from [gem5.TnT](https://github.com/tukl-msd/gem5.TnT) to install gem5, build it, get some benchmark programs and learn more about gem5. +Optionally, use the scripts from [gem5.TnT] to install gem5, build it, get some benchmark programs and learn more about gem5. In order to understand the SystemC coupling with gem5 it is recommended to read the documentation in the gem5 repository *util/tlm/README* and [12]. @@ -1567,7 +1567,7 @@ Wait some minutes for the bubble sort application to finish. The hello application binary was copied from gem5 repository. -The bubble sort application was obtained with [gem5.TnT](https://github.com/tukl-msd/gem5.TnT). +The bubble sort application was obtained with [gem5.TnT]. Command template for generating **.ini** configuration files follows: @@ -1727,11 +1727,8 @@ If you need help please contact Matthias Jung. ### DRAMSys + GEM5 Log Collector Scripts Users can profit of running multiple **DRAMSys + gem5** simulations -automatically with -[gem5ilva.sh](DRAMSys/library/resources/scripts/DRAMSylva/gem5ilva.sh) for **gem5 -syscall emulation (SE) mode** and -[gem5ilva_fs.sh](DRAMSys/library/resources/scripts/DRAMSylva/gem5ilva_fs.sh) for -**gem5 full system (FS) mode**. +automatically with [gem5ilva.sh] for **gem5 syscall emulation (SE) mode** and +[gem5ilva_fs.sh] for **gem5 full system (FS) mode**. Normally you will have to push your changes before running the scripts. This approach makes it easier to track back what exactly was tested by the scripts. @@ -1763,46 +1760,43 @@ the main repository (usually because they are too big to be added to the repository). For those cases uncomment and properly set the variable -**external_inifile_path** in -[gem5ilva_fs.sh](DRAMSys/library/resources/scripts/DRAMSylva/gem5ilva_fs.sh). +**external_inifile_path** in [gem5ilva_fs.sh]. This allows you to use a gem5 **config.ini** file external to the repository. Note, however, that in this case it is up to you to keep track of your simulation setup. **Hint:** -[gem5.TnT](https://github.com/tukl-msd/gem5.TnT) provides convenience scripts +[gem5.TnT] provides convenience scripts to create gem5 disk images with benchmarking programs embedded. -### Notes for [Elwetritsch](https://elwe.rhrk.uni-kl.de/) Users +### Notes for [Elwetritsch] Users -Firstly, take a look at [High Performance Computing at the TU -Kaiserslautern](https://elwe.rhrk.uni-kl.de/). +Firstly, take a look at [High Performance Computing at the TU Kaiserslautern](https://elwe.rhrk.uni-kl.de/). After that, please give yourself a change to learn a bit about [Batch Usage at RHRK TU Kaiserslautern](https://elwe.rhrk.uni-kl.de/elwetritsch/batch.shtml). This will probably save you some time later on. -When using DRAMSys + gem5 on the [Elwetritsch](https://elwe.rhrk.uni-kl.de/) -gem5 can be installed with convenience scripts provided by -[gem5.TnT](https://github.com/tukl-msd/gem5.TnT). +When using DRAMSys + gem5 on the [Elwetritsch] gem5 can be installed with +convenience scripts provided by [gem5.TnT]. -[gem5.TnT](https://github.com/tukl-msd/gem5.TnT) also provides convenience scripts +[gem5.TnT] also provides convenience scripts to create gem5 disk images with benchmarking programs embedded. The creation of disk images for gem5 requires superuser privilege. A solution is to copy (e.g., using scp or mounting a folder, etc.) the locally created disk images -to Elwetritsch. Since there is no compilation involved, copying disk images +to [Elwetritsch]. Since there is no compilation involved, copying disk images created in one machine to another machine should not incur in incompatibility problems. -On gem5.TnT repository open a gem5.TnT config file. +On [gem5.TnT] repository open a [gem5.TnT] config file. ```bash $ vim common/defaults.in ``` Note the variable **ROOTDIR**. Its default value is *ROOTDIR=$HOME/gem5_tnt*. -That means that gem5.TnT will download to *$HOME/gem5_tnt*. +That means that [gem5.TnT] will download to *$HOME/gem5_tnt*. Currently the space one can use in its Elwetrich *$HOME* folder is limited to a few tens of GiB. Nevertheless, a directory **/scratch/$USER** is provided @@ -1817,7 +1811,7 @@ $ cd $ ln -s /scratch/$USER/gem5_tnt ``` -On gem5.TnT repository use the commands below to get files and build gem5: +On [gem5.TnT] repository use the commands below to get files and build gem5: ```bash $ ./get_essential_fs.sh @@ -1829,14 +1823,12 @@ $ ./build_gem5.sh To get DRAMSys installed follow the traditional setup instructions described in this document. -For building DRAMSys one can profit from using -[DRAMSylva.sh](DRAMSys/library/resources/scripts/DRAMSylva/DRAMSylva.sh) which -loads the modules that are necessary for building DRAMSys on Elwetritsch. +For building DRAMSys one can profit from using [DRAMSylva.sh] which loads the +modules that are necessary for building DRAMSys on [Elwetritsch]. Regarding dependencies for building DRAMSys and DRAMSys + gem5, the scripts -provided inside the [DRAMSylva -folder](DRAMSys/library/resources/scripts/DRAMSylva), when running on -Elwetritsch, will load the required modules automatically. +provided inside the [DRAMSylva folder], when running on [Elwetritsch], will +load the required modules automatically. As usual, one may export environment variables from his/her **~/.bashrc** file on Elwetritch. Some segments extracted from a functional ~/.bashrc file are @@ -1877,10 +1869,9 @@ unset TMOUT ``` [SLURM](https://slurm.schedmd.com/overview.html) **job scripts** are available -inside the [DRAMSylva](DRAMSys/library/resources/scripts/DRAMSylva) folder. -They can be used directly without changes or as examples on how to start jobs -using nodes of the Elwetritsch cluster. Of course, one can create his/her own -job scripts. +inside the [DRAMSylva folder]. They can be used directly without changes or as +examples on how to start jobs using nodes of the [Elwetritsch] cluster. Of +course, one can create his/her own job scripts. ### Coverage Check @@ -1942,3 +1933,11 @@ Conference on Embedded Computer Systems Architectures Modeling and Simulation Portable Radhika Jagtap, Stephan Diestelhorst, Andreas Hansson, Matthias Jung and Norbert Wehn, IEEE International Conference on Embedded Computer Systems Architectures Modeling and Simulation (SAMOS), 2016, Samos Island, Greece. + +[gem5.TnT]: https://github.com/tukl-msd/gem5.TnT +[gem5ilva.sh]: DRAMSys/library/resources/scripts/DRAMSylva/gem5ilva.sh +[gem5ilva_fs.sh]: DRAMSys/library/resources/scripts/DRAMSylva/gem5ilva_fs.sh +[Elwetritsch]: https://elwe.rhrk.uni-kl.de/ +[DRAMSylva.sh]: DRAMSys/library/resources/scripts/DRAMSylva/DRAMSylva.sh +[DRAMSylva folder]: DRAMSys/library/resources/scripts/DRAMSylva +[configs_json]: DRAMSys/library/resources/scripts/DRAMSylva/configs_json From d2c99b9f1c3097632f058054b53eaa957a341bbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Wed, 20 Feb 2019 21:56:16 +0100 Subject: [PATCH 44/97] Doc and script updated --- README.md | 16 ++++++++++++---- utils/install_deb.sh | 17 +++++++++++++---- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 8ca1e149..30f6c52a 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,14 @@ $ ./getqwt.sh $ cd ~/qwt-6.1 ``` -After that add environment variables to your ~/.bashrc. +After that add environment variables to your ~/.bashrc. Open the file with a +text editor (e.g., nano, gedit, kate, notepad++, subl, atom, ultraedit, emacs, +vim, etc.). + +```bash +$ nano ~/.bashrc +``` + ```bash export LIBQWT_HOME=${HOME}/qwt-6.1/lib @@ -104,8 +111,9 @@ export LIBQWT_HEADERS=${HOME}/qwt-6.1/src export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}${LIBQWT_HOME} ``` -Remember to verify that the library and header files are located in paths you -specify. You can use the **ls** command to accomplish that. +Remember to verify that the library was created and the header files are +located in the paths you specify. You can use the **ls** command to accomplish +that. ```bash $ ls ${HOME}/qwt-6.1/lib @@ -116,7 +124,7 @@ Further information about Qwt can be found [here](http://qwt.sourceforge.net/). To grant flexibility to the user the paths where to find some essential libraries and headers can be specified with environment variables. Make sure -you have the environment variables below in your ~/.bashrc file. +you have the environment variables below defined in your ~/.bashrc file. **Note that some of the variables are automatically generated by the scripts. If you install the libraries in custom paths in your system you have to adapt the diff --git a/utils/install_deb.sh b/utils/install_deb.sh index 1b4f42d9..eae50784 100755 --- a/utils/install_deb.sh +++ b/utils/install_deb.sh @@ -32,17 +32,18 @@ # # Author: Éder F. Zulian +distro=$(cat /etc/os-release | grep "^ID=" | sed 's/.*=//' | awk '{print tolower($0)}') # Check distro. This script supports Debian/Ubuntu -distro=`lsb_release -is` -if [ "$distro" != "Debian" ] && [ "$distro" != "Ubuntu" ]; then +if [ "$distro" != "debian" ] && [ "$distro" != "ubuntu" ]; then echo -e "Error unsupported distribution (${distro}). This script supports Debian/Ubuntu." 1>&2 - exit 1 + exit 1 fi # Ensure the newest versions of all packages currently installed sudo apt-get update sudo apt-get upgrade -# Required dependencies +# Required dependencies and useful tools deplist=" +g++ libc6 libstdc++6 gitk @@ -70,6 +71,14 @@ libqt5svg5-dev libqt5sql5 libqt5widgets5 libqt5core5a +lsb-core +gedit +sublime-text +vim-gtk +kate +wget +gtkwave +openssh-server " for d in $deplist; do sudo apt-get -y install $d From d99417fcd893b01c71da6af17cd8b79c2ae4671a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Fri, 22 Feb 2019 11:12:46 +0100 Subject: [PATCH 45/97] Doc improved --- README.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 30f6c52a..775d17af 100644 --- a/README.md +++ b/README.md @@ -507,8 +507,8 @@ Below, the sub-configurations are listed and explained. - *NumberOfDevicesOnDIMM* (unsigned int) - Number of devices on dual inline memory module - *CheckTLM2Protocol* (boolean) - - "1": enables the TLM 2.0 Protocol Checking - - "0": disables the TLM 2.0 Protocol Checking + - "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 @@ -1263,10 +1263,11 @@ $ cd SuperLU_4.3/ $ cp MAKE_INC/make.linux make.inc ``` -Make sure the SuperLUroot variable in ./make.inc is properly set (in my case $(HOME)/repos/). +Make sure the SuperLUroot variable in ./make.inc is properly set. For example, +if you downloaded it to your home folder set as follows. ```bash -SuperLUroot = $(HOME)/repos/SuperLU_4.3 +SuperLUroot = $(HOME)/SuperLU_4.3 ``` Compile the library: @@ -1293,10 +1294,10 @@ $ cd 3d-ice-2.2.6 ``` Open the file makefile.def and set some variables. Set the correct path to the -SuperLU library you just compiled (in my case $(HOME)/repos/): +SuperLU library you just compiled. ```bash -SLU_MAIN = $(HOME)/repos/SuperLU_$(SLU_VERSION) +SLU_MAIN = $(HOME)/SuperLU_$(SLU_VERSION) ``` Set the YACC variable to bison-2.4.1: @@ -1305,14 +1306,14 @@ Set the YACC variable to bison-2.4.1: YACC = bison-2.4.1 ``` -Set the systemC architecture and main folder variables: +Set the following variables with proper values. ```bash -SYSTEMC_ARCH = [linux,linux64] -SYSTEMC_MAIN = $(HOME)/repos/systemc-$(SYSTEMC_VERSION) +SYSTEMC_ARCH = linux64 +SYSTEMC_MAIN = $(HOME)/systemc-2.3.1a ``` -Compile 3D-ICE with SystemC/TLM2.0 support: +Compile 3D-ICE with SystemC TLM-2.0 support: ```bash $ make clean @@ -1864,7 +1865,7 @@ export PYTHON_HEADERS=/usr/include/python3.4m # Gem5 + DRAMsys export GEM5=$HOME/gem5_tnt/gem5 -# Gem5 SystemC/TLM2.0 coupling (see also: $HOME/gem5_tnt/gem5/util/tlm/README) +# Gem5 SystemC TLM-2.0 coupling (see also: $HOME/gem5_tnt/gem5/util/tlm/README) export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${HOME}/gem5_tnt/gem5/build/ARM export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${SYSTEMC_HOME}/lib-$SYSTEMC_TARGET_ARCH export PKG_CONFIG_PATH=${PKG_CONFIG_PATH}:${SYSTEMC_HOME}/lib-$SYSTEMC_TARGET_ARCH/pkgconfig From 05e90d86cc70b57caeb169b57d0b7334aaab7bec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Fri, 22 Feb 2019 13:02:50 +0100 Subject: [PATCH 46/97] Doc improved --- README.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 775d17af..b80fda4c 100644 --- a/README.md +++ b/README.md @@ -1476,13 +1476,18 @@ path to gem5, for example in the *QtCreator under Projects > Build GEM5=/path/to/gem5/ ``` +Example: + +``` +GEM5=$HOME/gem5_tnt/gem5 +``` + Optionally, export environment variables in your **~/.bashrc** file or equivalent and open a new terminal: ```bash -# In this example gem5 is located at $HOME/gem5 (that is your home folder). -# Modify the variable to use the correct location. -export GEM5=$HOME/gem5 +# In this example gem5 is located at $HOME/gem5_tnt/gem5. +export GEM5=$HOME/gem5_tnt/gem5 # Add the folder containing libgem5_opt.so to the list where libraries should # be searched for. From 34bbf696dc525d89ec1c020e303be35d4e37f147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Tue, 26 Feb 2019 12:48:34 +0100 Subject: [PATCH 47/97] Script improved --- utils/install_deb.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/install_deb.sh b/utils/install_deb.sh index eae50784..2b5db391 100755 --- a/utils/install_deb.sh +++ b/utils/install_deb.sh @@ -79,6 +79,7 @@ kate wget gtkwave openssh-server +nautilus " for d in $deplist; do sudo apt-get -y install $d From 6bd1029d9eeadf8e1c4aff422b593e9b01927bdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Tue, 26 Feb 2019 16:00:41 +0100 Subject: [PATCH 48/97] script updated --- utils/install_deb.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/install_deb.sh b/utils/install_deb.sh index 2b5db391..31afe9e7 100755 --- a/utils/install_deb.sh +++ b/utils/install_deb.sh @@ -80,6 +80,7 @@ wget gtkwave openssh-server nautilus +telnet " for d in $deplist; do sudo apt-get -y install $d From 58fb41fef7744c252d23e649712c9917808f700f Mon Sep 17 00:00:00 2001 From: "Felipe S. Prado" Date: Thu, 28 Feb 2019 17:34:17 +0100 Subject: [PATCH 49/97] Redefine directory for .gcda files and adjust path to source code files --- .gitlab-ci.yml | 10 +++++++++- DRAMSys/tests/DDR3/ci.yml | 19 +++++++++++-------- DRAMSys/tests/WIDEIO/ci.yml | 9 +++++---- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f4776ac5..700ec923 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -22,12 +22,19 @@ build: - qmake ../DRAMSys/DRAMSys.pro - make -j4 - find . -name "*.o" -type f -delete + - rm -rf ${CI_PROJECT_DIR}/coverage + - mkdir -p ${CI_PROJECT_DIR}/coverage + cache: key: build paths: - build/ policy: push - + + artifacts: + paths: + - coverage/ + coverage: stage: Coverage coverage: '/Total:\|(\d+\.?\d+\%)/' @@ -37,6 +44,7 @@ coverage: - ls coverage/ -lah - lcov `find coverage -type f -exec echo "-a {}" \;` -o coverage/final.out - lcov --list coverage/final.out + artifacts: paths: - coverage/final.out diff --git a/DRAMSys/tests/DDR3/ci.yml b/DRAMSys/tests/DDR3/ci.yml index b92199d0..a5afa603 100644 --- a/DRAMSys/tests/DDR3/ci.yml +++ b/DRAMSys/tests/DDR3/ci.yml @@ -2,6 +2,8 @@ example_ddr3: stage: DDR3 script: + - export GCOV_PREFIX=$(pwd) + - export GCOV_PREFIX_STRIP=$(pwd | awk -F"/" '{print NF-1}') - cd build/simulator - ./DRAMSys ../../DRAMSys/tests/DDR3/simulations/ddr3-example.xml ../../DRAMSys/tests/DDR3/ - ls -lah @@ -11,15 +13,14 @@ example_ddr3: - cd ../traceAnalyzer - python3 ../../DRAMSys/traceAnalyzer/scripts/tests.py ../simulator/ddr3-example_ddr3_ch0.tdb | if ! grep "failed"; then exit 0; else exit 1; fi # Run Code Coverage - - mkdir -p ${CI_PROJECT_DIR}/coverage - - lcov -q -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out + - lcov -q -c --rc geninfo_adjust_src_path=$GCOV_PREFIX -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out cache: key: build paths: - build/ policy: pull - + artifacts: paths: - build/simulator/ddr3-example_ddr3_ch0.tdb @@ -30,6 +31,8 @@ example_ddr3: fr_fcfs: stage: DDR3 script: + - export GCOV_PREFIX=$(pwd) + - export GCOV_PREFIX_STRIP=$(pwd | awk -F"/" '{print NF-1}') - cd build/simulator - ./DRAMSys ../../DRAMSys/tests/DDR3/simulations/ddr3-fr_fcfs.xml ../../DRAMSys/tests/DDR3/ - ls -lah @@ -39,8 +42,7 @@ fr_fcfs: - cd ../traceAnalyzer - python3 ../../DRAMSys/traceAnalyzer/scripts/tests.py ../simulator/ddr3-fr_fcfs_ddr3_ch0.tdb | if ! grep "failed"; then exit 0; else exit 1; fi # Run Code Coverage - - mkdir -p ${CI_PROJECT_DIR}/coverage - - lcov -q -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out + - lcov -q -c --rc geninfo_adjust_src_path=$GCOV_PREFIX -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out cache: key: build @@ -56,17 +58,18 @@ fr_fcfs: - coverage/${CI_JOB_NAME}.out expire_in: 2 days -# Testing with TLM Protocol Cchecker +# Testing with TLM Protocol Checker protocol_checker: stage: DDR3 script: + - export GCOV_PREFIX=$(pwd) + - export GCOV_PREFIX_STRIP=$(pwd | awk -F"/" '{print NF-1}') - cd build/simulator - ./DRAMSys ../../DRAMSys/tests/DDR3/simulations/ddr3-protocol_checker.xml ../../DRAMSys/tests/DDR3/ > output.txt - echo "TODO" - ls -lah # Run Code Coverage - - mkdir -p ${CI_PROJECT_DIR}/coverage - - lcov -q -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out + - lcov -q -c --rc geninfo_adjust_src_path=$GCOV_PREFIX -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out cache: key: build diff --git a/DRAMSys/tests/WIDEIO/ci.yml b/DRAMSys/tests/WIDEIO/ci.yml index 2b79cb5b..e04215e0 100644 --- a/DRAMSys/tests/WIDEIO/ci.yml +++ b/DRAMSys/tests/WIDEIO/ci.yml @@ -2,10 +2,12 @@ example_wideio: stage: WIDEIO script: + - export GCOV_PREFIX=$(pwd) + - export GCOV_PREFIX_STRIP=$(pwd | awk -F"/" '{print NF-1}') # Generate specific traces for WIDEIO: - cd DRAMSys/tests/WIDEIO/traces/ - perl generator.pl - - cd ../../../../ + - cd - # Run DRAMSys - cd build/simulator - ./DRAMSys ../../DRAMSys/tests/WIDEIO/simulations/wideio-example.xml ../../DRAMSys/tests/WIDEIO/ @@ -17,15 +19,14 @@ example_wideio: - python3 ../../DRAMSys/traceAnalyzer/scripts/tests.py ../simulator/wideio-example_wideio_ch2.tdb | if ! grep "failed"; then exit 0; else exit 1; fi - python3 ../../DRAMSys/traceAnalyzer/scripts/tests.py ../simulator/wideio-example_wideio_ch3.tdb | if ! grep "failed"; then exit 0; else exit 1; fi # Run Code Coverage - - mkdir -p ${CI_PROJECT_DIR}/coverage - - lcov -q -c -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out + - lcov -q -c --rc geninfo_adjust_src_path=$GCOV_PREFIX -d ${CI_PROJECT_DIR}/build/ -o ${CI_PROJECT_DIR}/coverage/${CI_JOB_NAME}.out cache: key: build paths: - build/ policy: pull - + allow_failure: true # TODO: should be removed once the problems are fixed! artifacts: From e4b1884c059ff6bc5d0b6a1eaa3d46ec815ecf20 Mon Sep 17 00:00:00 2001 From: Felipe Salerno Prado Date: Fri, 1 Mar 2019 10:32:53 +0100 Subject: [PATCH 50/97] Resolve "BEGIN_RESP Exclusion Rule violation when using ClosePagePolicy" --- DRAMSys/library/src/controller/Controller.cpp | 16 ++++++++++++++-- DRAMSys/library/src/controller/Controller.h | 1 + 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/DRAMSys/library/src/controller/Controller.cpp b/DRAMSys/library/src/controller/Controller.cpp index b322b1cc..ebe31027 100644 --- a/DRAMSys/library/src/controller/Controller.cpp +++ b/DRAMSys/library/src/controller/Controller.cpp @@ -289,7 +289,13 @@ void Controller::frontendPEQCallback(tlm_generic_payload &payload, } payloadLeavesSystem(payload); + responseQueue.pop(); payload.release(); + + if(!responseQueue.empty()) { + sendToFrontend(*(responseQueue.front()), BEGIN_RESP, SC_ZERO_TIME); + } + } else { SC_REPORT_FATAL(0, "Front-end PEQ in controller wrapper was triggered with unknown phase"); @@ -412,9 +418,15 @@ void Controller::dramPEQCallback(tlm_generic_payload &payload, to_string(bank.ID()) + " from DRAM"); if (phase == END_RD || phase == END_WR) { - sendToFrontend(payload, BEGIN_RESP, SC_ZERO_TIME); + if(responseQueue.empty()) { + sendToFrontend(payload, BEGIN_RESP, SC_ZERO_TIME); + } + responseQueue.push(&payload); } else if (phase == END_RDA || phase == END_WRA) { - sendToFrontend(payload, BEGIN_RESP, SC_ZERO_TIME); + if(responseQueue.empty()) { + sendToFrontend(payload, BEGIN_RESP, SC_ZERO_TIME); + } + responseQueue.push(&payload); scheduleNextFromScheduler(bank); } else if (phase == END_REFA) { printDebugMessage("Finished auto refresh on all banks "); diff --git a/DRAMSys/library/src/controller/Controller.h b/DRAMSys/library/src/controller/Controller.h index efaae49e..c309c02d 100644 --- a/DRAMSys/library/src/controller/Controller.h +++ b/DRAMSys/library/src/controller/Controller.h @@ -157,6 +157,7 @@ protected: std::map numberOfPayloadsInSystem; std::vector refreshCollisionRequets; tlm::tlm_generic_payload *backpressure = NULL; + std::queue responseQueue; tlm_utils::peq_with_cb_and_phase frontendPEQ; tlm_utils::peq_with_cb_and_phase dramPEQ; From d21088a18f593d3bae5077818a2648fed0c99805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Fri, 12 Apr 2019 15:00:32 +0200 Subject: [PATCH 51/97] Improvement --- DRAMSys/gem5/gem5_se/hello-x86/config.dot | 275 ++++++++++++ DRAMSys/gem5/gem5_se/hello-x86/config.dot.pdf | Bin 0 -> 18335 bytes DRAMSys/gem5/gem5_se/hello-x86/config.dot.svg | 193 +++++++++ DRAMSys/gem5/gem5_se/hello-x86/config.ini | 282 +++++++++++++ DRAMSys/gem5/gem5_se/hello-x86/config.json | 397 ++++++++++++++++++ DRAMSys/gem5/gem5_se/hello-x86/hello | Bin 0 -> 659099 bytes 6 files changed, 1147 insertions(+) create mode 100644 DRAMSys/gem5/gem5_se/hello-x86/config.dot create mode 100644 DRAMSys/gem5/gem5_se/hello-x86/config.dot.pdf create mode 100644 DRAMSys/gem5/gem5_se/hello-x86/config.dot.svg create mode 100644 DRAMSys/gem5/gem5_se/hello-x86/config.ini create mode 100644 DRAMSys/gem5/gem5_se/hello-x86/config.json create mode 100755 DRAMSys/gem5/gem5_se/hello-x86/hello diff --git a/DRAMSys/gem5/gem5_se/hello-x86/config.dot b/DRAMSys/gem5/gem5_se/hello-x86/config.dot new file mode 100644 index 00000000..8b3a6ae1 --- /dev/null +++ b/DRAMSys/gem5/gem5_se/hello-x86/config.dot @@ -0,0 +1,275 @@ +digraph G { +ranksep="1.3"; +subgraph cluster_root { +color="#000000"; +fillcolor="#bab6ae"; +fontcolor="#000000"; +fontname=Arial; +fontsize=14; +label="root \n: Root"; +shape=Mrecord; +style="rounded, filled"; +tooltip="eventq_index=0 full_system=false sim_quantum=0 time_sync_enable=false time_sync_period=100000000000 time_sync_spin_threshold=100000000"; +subgraph cluster_system { +color="#000000"; +fillcolor="#e4e7eb"; +fontcolor="#000000"; +fontname=Arial; +fontsize=14; +label="system \n: System"; +shape=Mrecord; +style="rounded, filled"; +tooltip="boot_osflags=a cache_line_size=64 clk_domain=system.clk_domain default_p_state=UNDEFINED eventq_index=0 exit_on_work_items=false init_param=0 kernel= kernel_addr_check=false kernel_extras= kvm_vm=Null load_addr_mask=18446744073709551615 load_offset=0 mem_mode=timing mem_ranges=0:536870911:0:0:0:0 memories=system.physmem mmap_using_noreserve=false multi_thread=false num_work_ids=16 p_state_clk_gate_bins=20 p_state_clk_gate_max=1000000000000 p_state_clk_gate_min=1000 power_model= readfile= symbolfile= thermal_components= thermal_model=Null work_begin_ckpt_count=0 work_begin_cpu_id_exit=-1 work_begin_exit_count=0 work_cpus_ckpt_count=0 work_end_ckpt_count=0 work_end_exit_count=0 work_item_id=-1"; +system_system_port [color="#000000", fillcolor="#b6b8bc", fontcolor="#000000", fontname=Arial, fontsize=14, label=system_port, shape=Mrecord, style="rounded, filled"]; +subgraph cluster_system_membus { +color="#000000"; +fillcolor="#6f798c"; +fontcolor="#000000"; +fontname=Arial; +fontsize=14; +label="membus \n: SystemXBar"; +shape=Mrecord; +style="rounded, filled"; +tooltip="clk_domain=system.clk_domain default_p_state=UNDEFINED eventq_index=0 forward_latency=4 frontend_latency=3 p_state_clk_gate_bins=20 p_state_clk_gate_max=1000000000000 p_state_clk_gate_min=1000 point_of_coherency=true point_of_unification=true power_model= response_latency=2 snoop_filter=system.membus.snoop_filter snoop_response_latency=4 system=system use_default_range=false width=16"; +system_membus_master [color="#000000", fillcolor="#586070", fontcolor="#000000", fontname=Arial, fontsize=14, label=master, shape=Mrecord, style="rounded, filled"]; +system_membus_slave [color="#000000", fillcolor="#586070", fontcolor="#000000", fontname=Arial, fontsize=14, label=slave, shape=Mrecord, style="rounded, filled"]; +subgraph cluster_system_membus_snoop_filter { +color="#000000"; +fillcolor="#bab6ae"; +fontcolor="#000000"; +fontname=Arial; +fontsize=14; +label="snoop_filter \n: SnoopFilter"; +shape=Mrecord; +style="rounded, filled"; +tooltip="eventq_index=0 lookup_latency=1 max_capacity=8388608 system=system"; +} + +} + +subgraph cluster_system_external_memory { +color="#000000"; +fillcolor="#bab6ae"; +fontcolor="#000000"; +fontname=Arial; +fontsize=14; +label="external_memory \n: ExternalSlave"; +shape=Mrecord; +style="rounded, filled"; +tooltip="addr_ranges=0:536870911:0:0:0:0 clk_domain=system.clk_domain default_p_state=UNDEFINED eventq_index=0 p_state_clk_gate_bins=20 p_state_clk_gate_max=1000000000000 p_state_clk_gate_min=1000 port_data=transactor port_type=tlm_slave power_model="; +system_external_memory_port [color="#000000", fillcolor="#94918b", fontcolor="#000000", fontname=Arial, fontsize=14, label=port, shape=Mrecord, style="rounded, filled"]; +} + +subgraph cluster_system_voltage_domain { +color="#000000"; +fillcolor="#bab6ae"; +fontcolor="#000000"; +fontname=Arial; +fontsize=14; +label="voltage_domain \n: VoltageDomain"; +shape=Mrecord; +style="rounded, filled"; +tooltip="eventq_index=0 voltage=1.0"; +} + +subgraph cluster_system_physmem { +color="#000000"; +fillcolor="#5e5958"; +fontcolor="#000000"; +fontname=Arial; +fontsize=14; +label="physmem \n: SimpleMemory"; +shape=Mrecord; +style="rounded, filled"; +tooltip="bandwidth=73.000000 clk_domain=system.clk_domain conf_table_reported=true default_p_state=UNDEFINED eventq_index=0 in_addr_map=true kvm_map=true latency=30000 latency_var=0 null=false p_state_clk_gate_bins=20 p_state_clk_gate_max=1000000000000 p_state_clk_gate_min=1000 power_model= range=0:134217727:0:0:0:0"; +} + +subgraph cluster_system_clk_domain { +color="#000000"; +fillcolor="#bab6ae"; +fontcolor="#000000"; +fontname=Arial; +fontsize=14; +label="clk_domain \n: SrcClockDomain"; +shape=Mrecord; +style="rounded, filled"; +tooltip="clock=1000 domain_id=-1 eventq_index=0 init_perf_level=0 voltage_domain=system.voltage_domain"; +} + +subgraph cluster_system_cpu_voltage_domain { +color="#000000"; +fillcolor="#bab6ae"; +fontcolor="#000000"; +fontname=Arial; +fontsize=14; +label="cpu_voltage_domain \n: VoltageDomain"; +shape=Mrecord; +style="rounded, filled"; +tooltip="eventq_index=0 voltage=1.0"; +} + +subgraph cluster_system_dvfs_handler { +color="#000000"; +fillcolor="#bab6ae"; +fontcolor="#000000"; +fontname=Arial; +fontsize=14; +label="dvfs_handler \n: DVFSHandler"; +shape=Mrecord; +style="rounded, filled"; +tooltip="domains= enable=false eventq_index=0 sys_clk_domain=system.clk_domain transition_latency=100000000"; +} + +subgraph cluster_system_cpu_clk_domain { +color="#000000"; +fillcolor="#bab6ae"; +fontcolor="#000000"; +fontname=Arial; +fontsize=14; +label="cpu_clk_domain \n: SrcClockDomain"; +shape=Mrecord; +style="rounded, filled"; +tooltip="clock=500 domain_id=-1 eventq_index=0 init_perf_level=0 voltage_domain=system.cpu_voltage_domain"; +} + +subgraph cluster_system_cpu { +color="#000000"; +fillcolor="#bbc6d9"; +fontcolor="#000000"; +fontname=Arial; +fontsize=14; +label="cpu \n: TimingSimpleCPU"; +shape=Mrecord; +style="rounded, filled"; +tooltip="branchPred=Null checker=Null clk_domain=system.cpu_clk_domain cpu_id=0 default_p_state=UNDEFINED do_checkpoint_insts=true do_quiesce=true do_statistics_insts=true dtb=system.cpu.dtb eventq_index=0 function_trace=false function_trace_start=0 interrupts=system.cpu.interrupts isa=system.cpu.isa itb=system.cpu.itb max_insts_all_threads=0 max_insts_any_thread=0 max_loads_all_threads=0 max_loads_any_thread=0 numThreads=1 p_state_clk_gate_bins=20 p_state_clk_gate_max=1000000000000 p_state_clk_gate_min=1000 power_gating_on_idle=false power_model= profile=0 progress_interval=0 pwr_gating_latency=300 simpoint_start_insts= socket_id=0 switched_out=false syscallRetryLatency=10000 system=system tracer=system.cpu.tracer wait_for_remote_gdb=false workload=system.cpu.workload"; +system_cpu_icache_port [color="#000000", fillcolor="#959ead", fontcolor="#000000", fontname=Arial, fontsize=14, label=icache_port, shape=Mrecord, style="rounded, filled"]; +system_cpu_dcache_port [color="#000000", fillcolor="#959ead", fontcolor="#000000", fontname=Arial, fontsize=14, label=dcache_port, shape=Mrecord, style="rounded, filled"]; +subgraph cluster_system_cpu_workload { +color="#000000"; +fillcolor="#bab6ae"; +fontcolor="#000000"; +fontname=Arial; +fontsize=14; +label="workload \n: Process"; +shape=Mrecord; +style="rounded, filled"; +tooltip="cmd=tests/test-progs/hello/bin/x86/linux/hello cwd=/media/disk2/gem5_tnt/gem5 drivers= egid=100 env= errout=cerr euid=100 eventq_index=0 executable=tests/test-progs/hello/bin/x86/linux/hello gid=100 input=cin kvmInSE=false maxStackSize=67108864 output=cout pgid=100 pid=100 ppid=0 simpoint=0 system=system uid=100 useArchPT=false"; +} + +subgraph cluster_system_cpu_apic_clk_domain { +color="#000000"; +fillcolor="#bab6ae"; +fontcolor="#000000"; +fontname=Arial; +fontsize=14; +label="apic_clk_domain \n: DerivedClockDomain"; +shape=Mrecord; +style="rounded, filled"; +tooltip="clk_divider=16 clk_domain=system.cpu_clk_domain eventq_index=0"; +} + +subgraph cluster_system_cpu_dtb { +color="#000000"; +fillcolor="#bab6ae"; +fontcolor="#000000"; +fontname=Arial; +fontsize=14; +label="dtb \n: X86TLB"; +shape=Mrecord; +style="rounded, filled"; +tooltip="eventq_index=0 size=64 walker=system.cpu.dtb.walker"; +subgraph cluster_system_cpu_dtb_walker { +color="#000000"; +fillcolor="#9f9c95"; +fontcolor="#000000"; +fontname=Arial; +fontsize=14; +label="walker \n: X86PagetableWalker"; +shape=Mrecord; +style="rounded, filled"; +tooltip="clk_domain=system.cpu_clk_domain default_p_state=UNDEFINED eventq_index=0 num_squash_per_cycle=4 p_state_clk_gate_bins=20 p_state_clk_gate_max=1000000000000 p_state_clk_gate_min=1000 power_model= system=system"; +system_cpu_dtb_walker_port [color="#000000", fillcolor="#7f7c77", fontcolor="#000000", fontname=Arial, fontsize=14, label=port, shape=Mrecord, style="rounded, filled"]; +} + +} + +subgraph cluster_system_cpu_interrupts { +color="#000000"; +fillcolor="#c7a793"; +fontcolor="#000000"; +fontname=Arial; +fontsize=14; +label="interrupts \n: X86LocalApic"; +shape=Mrecord; +style="rounded, filled"; +tooltip="clk_domain=system.cpu.apic_clk_domain default_p_state=UNDEFINED eventq_index=0 int_latency=1000 p_state_clk_gate_bins=20 p_state_clk_gate_max=1000000000000 p_state_clk_gate_min=1000 pio_addr=2305843009213693952 pio_latency=100000 power_model= system=system"; +system_cpu_interrupts_int_slave [color="#000000", fillcolor="#9f8575", fontcolor="#000000", fontname=Arial, fontsize=14, label=int_slave, shape=Mrecord, style="rounded, filled"]; +system_cpu_interrupts_int_master [color="#000000", fillcolor="#9f8575", fontcolor="#000000", fontname=Arial, fontsize=14, label=int_master, shape=Mrecord, style="rounded, filled"]; +system_cpu_interrupts_pio [color="#000000", fillcolor="#9f8575", fontcolor="#000000", fontname=Arial, fontsize=14, label=pio, shape=Mrecord, style="rounded, filled"]; +} + +subgraph cluster_system_cpu_itb { +color="#000000"; +fillcolor="#bab6ae"; +fontcolor="#000000"; +fontname=Arial; +fontsize=14; +label="itb \n: X86TLB"; +shape=Mrecord; +style="rounded, filled"; +tooltip="eventq_index=0 size=64 walker=system.cpu.itb.walker"; +subgraph cluster_system_cpu_itb_walker { +color="#000000"; +fillcolor="#9f9c95"; +fontcolor="#000000"; +fontname=Arial; +fontsize=14; +label="walker \n: X86PagetableWalker"; +shape=Mrecord; +style="rounded, filled"; +tooltip="clk_domain=system.cpu_clk_domain default_p_state=UNDEFINED eventq_index=0 num_squash_per_cycle=4 p_state_clk_gate_bins=20 p_state_clk_gate_max=1000000000000 p_state_clk_gate_min=1000 power_model= system=system"; +system_cpu_itb_walker_port [color="#000000", fillcolor="#7f7c77", fontcolor="#000000", fontname=Arial, fontsize=14, label=port, shape=Mrecord, style="rounded, filled"]; +} + +} + +subgraph cluster_system_cpu_isa { +color="#000000"; +fillcolor="#bab6ae"; +fontcolor="#000000"; +fontname=Arial; +fontsize=14; +label="isa \n: X86ISA"; +shape=Mrecord; +style="rounded, filled"; +tooltip="eventq_index=0"; +} + +subgraph cluster_system_cpu_tracer { +color="#000000"; +fillcolor="#bab6ae"; +fontcolor="#000000"; +fontname=Arial; +fontsize=14; +label="tracer \n: ExeTracer"; +shape=Mrecord; +style="rounded, filled"; +tooltip="eventq_index=0"; +} + +} + +} + +} + +system_system_port -> system_membus_slave; +system_membus_master -> system_cpu_interrupts_pio; +system_membus_master -> system_cpu_interrupts_int_slave; +system_membus_master -> system_external_memory_port; +system_cpu_icache_port -> system_membus_slave; +system_cpu_dcache_port -> system_membus_slave; +system_cpu_dtb_walker_port -> system_membus_slave; +system_cpu_interrupts_int_master -> system_membus_slave; +system_cpu_itb_walker_port -> system_membus_slave; +} diff --git a/DRAMSys/gem5/gem5_se/hello-x86/config.dot.pdf b/DRAMSys/gem5/gem5_se/hello-x86/config.dot.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e1f465e94cd67dd648e99a8f03073c4ab00c4b78 GIT binary patch literal 18335 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 literal 0 HcmV?d00001 diff --git a/DRAMSys/gem5/gem5_se/hello-x86/config.dot.svg b/DRAMSys/gem5/gem5_se/hello-x86/config.dot.svg new file mode 100644 index 00000000..d2c806f2 --- /dev/null +++ b/DRAMSys/gem5/gem5_se/hello-x86/config.dot.svg @@ -0,0 +1,193 @@ + + + + + + +G + +cluster_root + + +root +: Root + + + +cluster_system + + +system +: System + + + +cluster_system_membus + + +membus +: SystemXBar + + + +cluster_system_external_memory + + +external_memory +: ExternalSlave + + + +cluster_system_cpu + + +cpu +: TimingSimpleCPU + + + +cluster_system_cpu_dtb + + +dtb +: X86TLB + + + +cluster_system_cpu_dtb_walker + + +walker +: X86PagetableWalker + + + +cluster_system_cpu_interrupts + + +interrupts +: X86LocalApic + + + +cluster_system_cpu_itb + + +itb +: X86TLB + + + +cluster_system_cpu_itb_walker + + +walker +: X86PagetableWalker + + + + +system_system_port + +system_port + + +system_membus_slave + +slave + + +system_system_port->system_membus_slave + + + + +system_membus_master + +master + + +system_external_memory_port + +port + + +system_membus_master->system_external_memory_port + + + + +system_cpu_interrupts_int_slave + +int_slave + + +system_membus_master->system_cpu_interrupts_int_slave + + + + +system_cpu_interrupts_pio + +pio + + +system_membus_master->system_cpu_interrupts_pio + + + + +system_cpu_icache_port + +icache_port + + +system_cpu_icache_port->system_membus_slave + + + + +system_cpu_dcache_port + +dcache_port + + +system_cpu_dcache_port->system_membus_slave + + + + +system_cpu_dtb_walker_port + +port + + +system_cpu_dtb_walker_port->system_membus_slave + + + + +system_cpu_interrupts_int_master + +int_master + + +system_cpu_interrupts_int_master->system_membus_slave + + + + +system_cpu_itb_walker_port + +port + + +system_cpu_itb_walker_port->system_membus_slave + + + + + diff --git a/DRAMSys/gem5/gem5_se/hello-x86/config.ini b/DRAMSys/gem5/gem5_se/hello-x86/config.ini new file mode 100644 index 00000000..52972f4b --- /dev/null +++ b/DRAMSys/gem5/gem5_se/hello-x86/config.ini @@ -0,0 +1,282 @@ +[root] +type=Root +children=system +eventq_index=0 +full_system=false +sim_quantum=0 +time_sync_enable=false +time_sync_period=100000000000 +time_sync_spin_threshold=100000000 + +[system] +type=System +children=clk_domain cpu cpu_clk_domain cpu_voltage_domain dvfs_handler external_memory membus physmem voltage_domain +boot_osflags=a +cache_line_size=64 +clk_domain=system.clk_domain +default_p_state=UNDEFINED +eventq_index=0 +exit_on_work_items=false +init_param=0 +kernel= +kernel_addr_check=false +kernel_extras= +kvm_vm=Null +load_addr_mask=18446744073709551615 +load_offset=0 +mem_mode=timing +mem_ranges=0:536870911:0:0:0:0 +memories=system.physmem +mmap_using_noreserve=false +multi_thread=false +num_work_ids=16 +p_state_clk_gate_bins=20 +p_state_clk_gate_max=1000000000000 +p_state_clk_gate_min=1000 +power_model= +readfile= +symbolfile= +thermal_components= +thermal_model=Null +work_begin_ckpt_count=0 +work_begin_cpu_id_exit=-1 +work_begin_exit_count=0 +work_cpus_ckpt_count=0 +work_end_ckpt_count=0 +work_end_exit_count=0 +work_item_id=-1 +system_port=system.membus.slave[0] + +[system.clk_domain] +type=SrcClockDomain +clock=1000 +domain_id=-1 +eventq_index=0 +init_perf_level=0 +voltage_domain=system.voltage_domain + +[system.cpu] +type=TimingSimpleCPU +children=apic_clk_domain dtb interrupts isa itb tracer workload +branchPred=Null +checker=Null +clk_domain=system.cpu_clk_domain +cpu_id=0 +default_p_state=UNDEFINED +do_checkpoint_insts=true +do_quiesce=true +do_statistics_insts=true +dtb=system.cpu.dtb +eventq_index=0 +function_trace=false +function_trace_start=0 +interrupts=system.cpu.interrupts +isa=system.cpu.isa +itb=system.cpu.itb +max_insts_all_threads=0 +max_insts_any_thread=0 +max_loads_all_threads=0 +max_loads_any_thread=0 +numThreads=1 +p_state_clk_gate_bins=20 +p_state_clk_gate_max=1000000000000 +p_state_clk_gate_min=1000 +power_gating_on_idle=false +power_model= +profile=0 +progress_interval=0 +pwr_gating_latency=300 +simpoint_start_insts= +socket_id=0 +switched_out=false +syscallRetryLatency=10000 +system=system +tracer=system.cpu.tracer +wait_for_remote_gdb=false +workload=system.cpu.workload +dcache_port=system.membus.slave[2] +icache_port=system.membus.slave[1] + +[system.cpu.apic_clk_domain] +type=DerivedClockDomain +clk_divider=16 +clk_domain=system.cpu_clk_domain +eventq_index=0 + +[system.cpu.dtb] +type=X86TLB +children=walker +eventq_index=0 +size=64 +walker=system.cpu.dtb.walker + +[system.cpu.dtb.walker] +type=X86PagetableWalker +clk_domain=system.cpu_clk_domain +default_p_state=UNDEFINED +eventq_index=0 +num_squash_per_cycle=4 +p_state_clk_gate_bins=20 +p_state_clk_gate_max=1000000000000 +p_state_clk_gate_min=1000 +power_model= +system=system +port=system.membus.slave[4] + +[system.cpu.interrupts] +type=X86LocalApic +clk_domain=system.cpu.apic_clk_domain +default_p_state=UNDEFINED +eventq_index=0 +int_latency=1000 +p_state_clk_gate_bins=20 +p_state_clk_gate_max=1000000000000 +p_state_clk_gate_min=1000 +pio_addr=2305843009213693952 +pio_latency=100000 +power_model= +system=system +int_master=system.membus.slave[5] +int_slave=system.membus.master[1] +pio=system.membus.master[0] + +[system.cpu.isa] +type=X86ISA +eventq_index=0 + +[system.cpu.itb] +type=X86TLB +children=walker +eventq_index=0 +size=64 +walker=system.cpu.itb.walker + +[system.cpu.itb.walker] +type=X86PagetableWalker +clk_domain=system.cpu_clk_domain +default_p_state=UNDEFINED +eventq_index=0 +num_squash_per_cycle=4 +p_state_clk_gate_bins=20 +p_state_clk_gate_max=1000000000000 +p_state_clk_gate_min=1000 +power_model= +system=system +port=system.membus.slave[3] + +[system.cpu.tracer] +type=ExeTracer +eventq_index=0 + +[system.cpu.workload] +type=Process +cmd=../../DRAMSys/gem5/gem5_se/hello-x86/hello +cwd= +drivers= +egid=100 +env= +errout=cerr +euid=100 +eventq_index=0 +executable=../../DRAMSys/gem5/gem5_se/hello-x86/hello +gid=100 +input=cin +kvmInSE=false +maxStackSize=67108864 +output=cout +pgid=100 +pid=100 +ppid=0 +simpoint=0 +system=system +uid=100 +useArchPT=false + +[system.cpu_clk_domain] +type=SrcClockDomain +clock=500 +domain_id=-1 +eventq_index=0 +init_perf_level=0 +voltage_domain=system.cpu_voltage_domain + +[system.cpu_voltage_domain] +type=VoltageDomain +eventq_index=0 +voltage=1.0 + +[system.dvfs_handler] +type=DVFSHandler +domains= +enable=false +eventq_index=0 +sys_clk_domain=system.clk_domain +transition_latency=100000000 + +[system.external_memory] +type=ExternalSlave +addr_ranges=0:536870911:0:0:0:0 +clk_domain=system.clk_domain +default_p_state=UNDEFINED +eventq_index=0 +p_state_clk_gate_bins=20 +p_state_clk_gate_max=1000000000000 +p_state_clk_gate_min=1000 +port_data=transactor +port_type=tlm_slave +power_model= +port=system.membus.master[2] + +[system.membus] +type=CoherentXBar +children=snoop_filter +clk_domain=system.clk_domain +default_p_state=UNDEFINED +eventq_index=0 +forward_latency=4 +frontend_latency=3 +p_state_clk_gate_bins=20 +p_state_clk_gate_max=1000000000000 +p_state_clk_gate_min=1000 +point_of_coherency=true +point_of_unification=true +power_model= +response_latency=2 +snoop_filter=system.membus.snoop_filter +snoop_response_latency=4 +system=system +use_default_range=false +width=16 +master=system.cpu.interrupts.pio system.cpu.interrupts.int_slave system.external_memory.port +slave=system.system_port system.cpu.icache_port system.cpu.dcache_port system.cpu.itb.walker.port system.cpu.dtb.walker.port system.cpu.interrupts.int_master + +[system.membus.snoop_filter] +type=SnoopFilter +eventq_index=0 +lookup_latency=1 +max_capacity=8388608 +system=system + +[system.physmem] +type=SimpleMemory +bandwidth=73.000000 +clk_domain=system.clk_domain +conf_table_reported=true +default_p_state=UNDEFINED +eventq_index=0 +in_addr_map=true +kvm_map=true +latency=30000 +latency_var=0 +null=false +p_state_clk_gate_bins=20 +p_state_clk_gate_max=1000000000000 +p_state_clk_gate_min=1000 +power_model= +range=0:134217727:0:0:0:0 + +[system.voltage_domain] +type=VoltageDomain +eventq_index=0 +voltage=1.0 + diff --git a/DRAMSys/gem5/gem5_se/hello-x86/config.json b/DRAMSys/gem5/gem5_se/hello-x86/config.json new file mode 100644 index 00000000..8b3e80bc --- /dev/null +++ b/DRAMSys/gem5/gem5_se/hello-x86/config.json @@ -0,0 +1,397 @@ +{ + "name": null, + "sim_quantum": 0, + "system": { + "kernel": "", + "mmap_using_noreserve": false, + "kernel_addr_check": false, + "membus": { + "point_of_coherency": true, + "system": "system", + "response_latency": 2, + "cxx_class": "CoherentXBar", + "forward_latency": 4, + "clk_domain": "system.clk_domain", + "point_of_unification": true, + "width": 16, + "eventq_index": 0, + "default_p_state": "UNDEFINED", + "p_state_clk_gate_max": 1000000000000, + "master": { + "peer": [ + "system.cpu.interrupts.pio", + "system.cpu.interrupts.int_slave", + "system.external_memory.port" + ], + "role": "MASTER" + }, + "type": "CoherentXBar", + "frontend_latency": 3, + "slave": { + "peer": [ + "system.system_port", + "system.cpu.icache_port", + "system.cpu.dcache_port", + "system.cpu.itb.walker.port", + "system.cpu.dtb.walker.port", + "system.cpu.interrupts.int_master" + ], + "role": "SLAVE" + }, + "p_state_clk_gate_min": 1000, + "snoop_filter": { + "name": "snoop_filter", + "system": "system", + "max_capacity": 8388608, + "eventq_index": 0, + "cxx_class": "SnoopFilter", + "path": "system.membus.snoop_filter", + "type": "SnoopFilter", + "lookup_latency": 1 + }, + "power_model": [], + "path": "system.membus", + "snoop_response_latency": 4, + "name": "membus", + "p_state_clk_gate_bins": 20, + "use_default_range": false + }, + "symbolfile": "", + "kvm_vm": null, + "readfile": "", + "thermal_model": null, + "cxx_class": "System", + "work_begin_cpu_id_exit": -1, + "load_offset": 0, + "work_begin_exit_count": 0, + "p_state_clk_gate_min": 1000, + "memories": [ + "system.physmem" + ], + "work_begin_ckpt_count": 0, + "clk_domain": { + "name": "clk_domain", + "clock": [ + 1000 + ], + "init_perf_level": 0, + "voltage_domain": "system.voltage_domain", + "eventq_index": 0, + "cxx_class": "SrcClockDomain", + "path": "system.clk_domain", + "type": "SrcClockDomain", + "domain_id": -1 + }, + "mem_ranges": [ + "0:536870911:0:0:0:0" + ], + "eventq_index": 0, + "default_p_state": "UNDEFINED", + "p_state_clk_gate_max": 1000000000000, + "dvfs_handler": { + "enable": false, + "name": "dvfs_handler", + "sys_clk_domain": "system.clk_domain", + "transition_latency": 100000000, + "eventq_index": 0, + "cxx_class": "DVFSHandler", + "domains": [], + "path": "system.dvfs_handler", + "type": "DVFSHandler" + }, + "work_end_exit_count": 0, + "type": "System", + "voltage_domain": { + "name": "voltage_domain", + "eventq_index": 0, + "voltage": [ + 1.0 + ], + "cxx_class": "VoltageDomain", + "path": "system.voltage_domain", + "type": "VoltageDomain" + }, + "cache_line_size": 64, + "external_memory": { + "name": "external_memory", + "p_state_clk_gate_min": 1000, + "p_state_clk_gate_bins": 20, + "default_p_state": "UNDEFINED", + "clk_domain": "system.clk_domain", + "power_model": [], + "addr_ranges": [ + "0:536870911:0:0:0:0" + ], + "eventq_index": 0, + "port_type": "tlm_slave", + "cxx_class": "ExternalSlave", + "p_state_clk_gate_max": 1000000000000, + "path": "system.external_memory", + "type": "ExternalSlave", + "port": { + "peer": "system.membus.master[2]", + "role": "SLAVE" + }, + "port_data": "transactor" + }, + "boot_osflags": "a", + "system_port": { + "peer": "system.membus.slave[0]", + "role": "MASTER" + }, + "physmem": { + "range": "0:134217727:0:0:0:0", + "latency": 30000, + "name": "physmem", + "p_state_clk_gate_min": 1000, + "eventq_index": 0, + "p_state_clk_gate_bins": 20, + "default_p_state": "UNDEFINED", + "kvm_map": true, + "clk_domain": "system.clk_domain", + "power_model": [], + "latency_var": 0, + "bandwidth": "73.000000", + "conf_table_reported": true, + "cxx_class": "SimpleMemory", + "p_state_clk_gate_max": 1000000000000, + "path": "system.physmem", + "null": false, + "type": "SimpleMemory", + "in_addr_map": true + }, + "power_model": [], + "work_cpus_ckpt_count": 0, + "thermal_components": [], + "path": "system", + "cpu_clk_domain": { + "name": "cpu_clk_domain", + "clock": [ + 500 + ], + "init_perf_level": 0, + "voltage_domain": "system.cpu_voltage_domain", + "eventq_index": 0, + "cxx_class": "SrcClockDomain", + "path": "system.cpu_clk_domain", + "type": "SrcClockDomain", + "domain_id": -1 + }, + "work_end_ckpt_count": 0, + "mem_mode": "timing", + "name": "system", + "init_param": 0, + "p_state_clk_gate_bins": 20, + "kernel_extras": [], + "load_addr_mask": 18446744073709551615, + "cpu": [ + { + "do_statistics_insts": true, + "numThreads": 1, + "itb": { + "name": "itb", + "eventq_index": 0, + "cxx_class": "X86ISA::TLB", + "walker": { + "name": "walker", + "p_state_clk_gate_min": 1000, + "p_state_clk_gate_bins": 20, + "cxx_class": "X86ISA::Walker", + "clk_domain": "system.cpu_clk_domain", + "power_model": [], + "system": "system", + "eventq_index": 0, + "default_p_state": "UNDEFINED", + "p_state_clk_gate_max": 1000000000000, + "path": "system.cpu.itb.walker", + "type": "X86PagetableWalker", + "port": { + "peer": "system.membus.slave[3]", + "role": "MASTER" + }, + "num_squash_per_cycle": 4 + }, + "path": "system.cpu.itb", + "type": "X86TLB", + "size": 64 + }, + "power_gating_on_idle": false, + "function_trace": false, + "do_checkpoint_insts": true, + "cxx_class": "TimingSimpleCPU", + "max_loads_all_threads": 0, + "system": "system", + "apic_clk_domain": { + "name": "apic_clk_domain", + "clk_domain": "system.cpu_clk_domain", + "eventq_index": 0, + "cxx_class": "DerivedClockDomain", + "path": "system.cpu.apic_clk_domain", + "type": "DerivedClockDomain", + "clk_divider": 16 + }, + "clk_domain": "system.cpu_clk_domain", + "function_trace_start": 0, + "cpu_id": 0, + "checker": null, + "eventq_index": 0, + "default_p_state": "UNDEFINED", + "p_state_clk_gate_max": 1000000000000, + "do_quiesce": true, + "type": "TimingSimpleCPU", + "profile": 0, + "icache_port": { + "peer": "system.membus.slave[1]", + "role": "MASTER" + }, + "p_state_clk_gate_bins": 20, + "p_state_clk_gate_min": 1000, + "syscallRetryLatency": 10000, + "interrupts": [ + { + "int_master": { + "peer": "system.membus.slave[5]", + "role": "MASTER" + }, + "name": "interrupts", + "p_state_clk_gate_min": 1000, + "pio": { + "peer": "system.membus.master[0]", + "role": "SLAVE" + }, + "int_slave": { + "peer": "system.membus.master[1]", + "role": "SLAVE" + }, + "p_state_clk_gate_bins": 20, + "cxx_class": "X86ISA::Interrupts", + "pio_latency": 100000, + "clk_domain": "system.cpu.apic_clk_domain", + "power_model": [], + "system": "system", + "int_latency": 1000, + "eventq_index": 0, + "default_p_state": "UNDEFINED", + "p_state_clk_gate_max": 1000000000000, + "path": "system.cpu.interrupts", + "pio_addr": 2305843009213693952, + "type": "X86LocalApic" + } + ], + "dcache_port": { + "peer": "system.membus.slave[2]", + "role": "MASTER" + }, + "socket_id": 0, + "power_model": [], + "max_insts_all_threads": 0, + "path": "system.cpu", + "pwr_gating_latency": 300, + "max_loads_any_thread": 0, + "switched_out": false, + "workload": [ + { + "uid": 100, + "pid": 100, + "kvmInSE": false, + "cxx_class": "Process", + "executable": "tests/test-progs/hello/bin/x86/linux/hello", + "drivers": [], + "system": "system", + "gid": 100, + "eventq_index": 0, + "env": [], + "maxStackSize": 67108864, + "ppid": 0, + "type": "Process", + "cwd": "/media/disk2/gem5_tnt/gem5", + "pgid": 100, + "simpoint": 0, + "euid": 100, + "input": "cin", + "path": "system.cpu.workload", + "name": "workload", + "cmd": [ + "tests/test-progs/hello/bin/x86/linux/hello" + ], + "errout": "cerr", + "useArchPT": false, + "egid": 100, + "output": "cout" + } + ], + "name": "cpu", + "wait_for_remote_gdb": false, + "dtb": { + "name": "dtb", + "eventq_index": 0, + "cxx_class": "X86ISA::TLB", + "walker": { + "name": "walker", + "p_state_clk_gate_min": 1000, + "p_state_clk_gate_bins": 20, + "cxx_class": "X86ISA::Walker", + "clk_domain": "system.cpu_clk_domain", + "power_model": [], + "system": "system", + "eventq_index": 0, + "default_p_state": "UNDEFINED", + "p_state_clk_gate_max": 1000000000000, + "path": "system.cpu.dtb.walker", + "type": "X86PagetableWalker", + "port": { + "peer": "system.membus.slave[4]", + "role": "MASTER" + }, + "num_squash_per_cycle": 4 + }, + "path": "system.cpu.dtb", + "type": "X86TLB", + "size": 64 + }, + "simpoint_start_insts": [], + "max_insts_any_thread": 0, + "progress_interval": 0, + "branchPred": null, + "isa": [ + { + "eventq_index": 0, + "path": "system.cpu.isa", + "type": "X86ISA", + "name": "isa", + "cxx_class": "X86ISA::ISA" + } + ], + "tracer": { + "eventq_index": 0, + "path": "system.cpu.tracer", + "type": "ExeTracer", + "name": "tracer", + "cxx_class": "Trace::ExeTracer" + } + } + ], + "multi_thread": false, + "cpu_voltage_domain": { + "name": "cpu_voltage_domain", + "eventq_index": 0, + "voltage": [ + 1.0 + ], + "cxx_class": "VoltageDomain", + "path": "system.cpu_voltage_domain", + "type": "VoltageDomain" + }, + "num_work_ids": 16, + "work_item_id": -1, + "exit_on_work_items": false + }, + "time_sync_period": 100000000000, + "eventq_index": 0, + "time_sync_spin_threshold": 100000000, + "cxx_class": "Root", + "path": "root", + "time_sync_enable": false, + "type": "Root", + "full_system": false +} \ No newline at end of file diff --git a/DRAMSys/gem5/gem5_se/hello-x86/hello b/DRAMSys/gem5/gem5_se/hello-x86/hello new file mode 100755 index 0000000000000000000000000000000000000000..a3ec8dcdb6bbc30a8e415c5c226fc6b09643822c GIT binary patch literal 659099 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�)&ml*m;+1KLKwCOSR;FybzGq0E40wP77>fH`*~# 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

?>c6s+vA!tF-$&blO(=iBia} za|yct+)u}uto}9QIc)!cVKnyX&ocT2&G!xmjcDel#ml}|X%DFFzX*DV-**FmkN)-W|igCv=27^CwM$J1-7{q5`cv9i#&Z!SK zy*sljGcWfipQ&_i&c5v(slwh86ie8bRt=&4ZZ>qi`JlLvi5&a_O2-55uLp}?6NN!N z2hsZl&P}r0y5Hxf-l>y06=_2qQHQvPDpMzr_+#XdYm1DkFU#XVcJMInlWccEXypJF8k@zjwn+vciwfiLM(&Kgd)iy6#GOz|S?S3ind0M}> zr@rCu1f1@UOVWcqn;zbFd(z0`SB>8>`ZHv}&`14DTyWcWQlrT_d^EqJChknowNztB z(a+^XA3m&w#Kwi+7Hs=xgPOv`@8n~-{$Pd2e?WSVDYeE_vlyi|lbnBzZ4J0-IGnbv31pjz7oMnE+Oky~D@zS)7bpS7k6DQgBVil7Fh?p{&YFnW=~R<1D0co8xz!V#0iEkI!eekDNuwP2I2cxO@i#rY=6&vU z<=T6CA^%fgdTvp(JzzGMF&zHLmUt_*f2`OHhBPwjWO5ph5+_4jM7uZfd!0VLb8-f} z$^P&umb27y-zpHinrJDcicOs9{Z5l#^$M%2{2WQve|$|=SuyBGDR*q_nn%S{NV;J; zs!u^@W{%iQsE(x8mv=R+E{WB9qg$1P8NJjVx5K!GaVHA+d3&2H`k6tSOSLJM(BXnt ztpaE+?ijhJU03~mtH4zkQ(35ayv`ut^31wFNC3fZpnxmroos?dfNUC|o0I5UAf`vM z(}X{RY_gxj{@x_oBJ)IVM2VDPfkcp82nLSFzWqn@IBn$3qfYmd3c0jfua0%%K(9%z z-s$9~{m8j?;dwIEC3Vi^hkf6fTn9|i5j7TuYt7bvo`i=$_s zB#MjC3o_ghs*sF&iWQeTEO$&k8raQ}D2lfkAK*O09geSXjGptX%%zqL&{>=lEZBjh zDbXmIGUv`zUD?Zyp}KP2t&*Qi;3X6kd*)HlfLT!~sjkJ5`b zudwSC4vZgis3yGE@uR`KI#y0%Q;T21klVlfgzCr(ItNzdG(SzRozf|}C zmfp?eclTf3hwf2Y^xr;f2%KFU2 z&A4UX2n#>AG&Cx*^`MBQ4##?-wnEV&8#2Bs1MfFS?i>$!-ya^`*{@INC`Tbn-NrjW zS;fgRuH>`@u+F&q1izqI(Vy1JdW`-PhKrK#%r1IHy>F}1)lyQJAfK||YvMr*$!WPl z&V(}h!59zXTuXb|RsOOWtYUefn9EtE0t6T_ z@%sUD@-8cKU`X{9aw;6j>Jx7R(!TjbCJJBm{lv{(^4Z%u0ygCfcF9@sgn*+QUzksz znzx5s&|Ai7pkI`DC}?*C3$~_|`oLj~w|80@3Cg-!yG36$DfI*Q)EU zb{k;J3$Z)csh%Jw;&0ho5`*Y(U#@BED|~o-(fyUO z1#fX{78-~Gyn8%2mTV6HS-MtPu)B;iZ3m9ul@0wCGP)N_?=l1<>~)C^f`9H|=S{EI z`q-JAHm7JK1HV#et*GF<=bf>`*F;V}fcnK~rS+}++>d1uu;0jWLiQbKnVJhSFzY8#xB8(QlcD4?u*u`S-%{^a4-gTh_w4~-a<2ESVT54P`(EJvTHfz8 z?{}v6J4b%!$5zzHuP=1rD*2I<)Y+n9G|)Y-qKShRA$3RXj*(C2$$H6z2H8OOTd8z6 zTS5_@yYI0cyXlcAW~SXWK#owNQQ-lh z!W%5xs808LzaCI3a=q_-@3++Z^#)&|1|PKlTAD%iUrxpZ74-k;KrrDffn>ahKj`1~ z7#w*NyDx-QeA0GiW`ty)o0Axj(v|gig^tut4i(n0BmdwusQbIGOoSz-KA~^%f1?KM zF3J@MXjUun%#n%oi%>@Lc%z)Cprq8+Rqur!dAitXk_UYh78L$*a!ys>((wzEAZicF zTPP$mGjj4C#m!M(#DkOlnE9+vyr;%1KK2#=nNu~4t197fA+Hl;`|=8UYslj%3ls0B zfGPc%i{qjWcz~*7xyD!Z*Ni_Z)SsB@Pk4r{t)Ru;klc{&Z`lk5BxRzY-}8|BzsRm! zFtp6Pf4!WT>xM9!(5oS7czWlIJ0~Hn zX|D%O9A_neF{r!yA%20$!|G=m=5W(;tI(=e+mjlU+M|S5M#SRMFsDYOJR!&UuCx?0 zX7eNe%8J*@qbDQIrR6f1Pvn5LWIsOL&tvp?==Cx^`M^gcMOU$iM47#NH*jVzh))3h zfS1FSPw~Y3_zm*OH&n%qa45Tr5AS;w-|?}e_c+ppXd=Fug{IGa*YbI2D^fv&5}#>oFzZCfksgW%@_|(BjGb|w? z?_7&_AA|}Ld)p+($dyttV+23)4-1;_0K9z{4fnC{0=w0RHujs+CSE~#FFaRJQ$rQuaC`7`6!6H9tzGueAgGbvYju5{!zg2QwxpbBHNO(BP-?MKx%XmLK0ZrAX2#ofnfjcQFDNCo}Qu?zOG^Bjh2{Iwx_o z*T3Sf&>$pXBDLVm)bR-?PsrGm+WXz;&zEb0%yxLY_%0fdrCvZ%l*Ax6>Cgj+y zWG-lz8ss}Wv0IH_hOU4h`=|3=h|_1fg5v$*<1pK-YhE%|9XGzkb#3NE&eapK0JYK_ z0vnb(GE9K$Mei~3hGd2yN#^VZ)JR!jGrY8&$basf;}cVe$#Vp&_~ht<8by2)S-kmZ zS4UD*{bXJ?YZWIkrc7%ui|bOSn$r-c{Nfj@rZ~ep*Jp$$nNLhgmKVF>5-a(lWmhW~ zI*0~e?Vc&k%^dNZ>0yO4yyk<9a6qcPQlCq{*HlAC-A(7v+mx*TuK>Z~{-Z_?lKel7 z?FGOs1~~7y*Y6QrTAmh{x_OS^YBR+nFBlIiNkcS>)txI!x}xfL<+Vb6u^s-waX#OaXx74)y$hvpZz4N`Zye#f}&{NdgH;14a&cDkTv z5j+y~`0R1Nt?6TY*ZED!R2wpcLr7Zu`6H&QOJD4hg%8VeSCU7CG)ML`^%=^`(woVT zQ>ku^ghXE1;{w2nu6PJ^SaSz|WR#X&3jF25uQ^-ze`{H?CU2H6bP@wY{bxg;$W}C1 zHhhO&o_ift*0NU!1!ox=>%W)d`|=D@znrd;^1908E-N|}O2wtx_AY4Q1<0t`^*^pU zQFN;dIxJ;8Sv6*T)^N-kb|z_o)avb)jUU|j0B)``i#F6}oeO}W0Fj-?B(U%*&F`q^ z>DI%uB;NF>~qCTLvqU9}Hg!OvrF zs)S||((_)4Qqk+hv}PNR^^6}PGiSxt%g#{5Rbu=fk|}14q#lWrWTdt+;~Yv!pW-DF z>ll5=fM*1S!Ac%2;~#n%TQPUPcRxVRRNLB#02)l^QU%?ZCM`I|aeOIIXgJwMp={&G zWr?Sk_g+o?3P`yse@{qoRi=SND~AIK)<+Iveg$zxv~|4P=2v;lk~bh4S}9zVZ4}dx zdVDW67Wwt&b5Je&s_<$*?=_yEs%FPsM+J4z*n#F%%Lpt#k!f+s~FF>)b{FL zqDmY-qHQs`0XgD`xE^1N)j(=Y1J#&*cWsX3XM0eSL}RZI!QNBCgTA7b4mxz{&W z{F!E-_SHydORkezu#m*N`KWc?-3ZIktP_5hgDhM{vP@CH)hCt85!RRMbFZW=Il`K? z$ADH=^dW8nSp@I;5DNwD{{#xwnsske-ikiy^NCZR5+BV_Hrp30_`p4%;@$ySo#3bN zE%!wza*&rz!QLXA8jD`hN%}1%&E+E8;ks+t0r{-{554~*oEs=e6Z%%CdnBT-BiIf+ z7zMWDMH^EC$o9EEtJVXskbA_8?|J+m`X`k5qYQ@k>j|nJTd26%qI~n;vR>IK{-y=o!FfH}`1r6f%jrM;FVu&8$7XyQPn)*K6q=ccjV||H5la z@L5ky}FrvYqH@IUcy~9Cb09 zrw8@7-OW`3@-?)Q4EGDbgJjdU6u;A3Akq*J;kB+e1L4qtk$1dm?R}HSR8LcoZC`z+ zo)`OVw~T5LqUm~9CjLtAMIUontOF{k$SkDfvTM*-zCw6kr6T)H${%-_|PO&4DNevYq6`sBWZxP=LkJ%|TJMvP zRMdVL%2_3afQ4Cm8P({$#ytz0j&!`*>Fl?mSM9`e-PTq)ASvvt|OkcXDf z>n{HoHR-el()5#s7SC$l#BiN)CjbnNlUVQ_{ESSInp(S$Y$n!Y7Br z;1v)?xiWiNHd{rm<16?~S8-~SB)ET}id7OyLkWF$>XLtP@k62#*@vl5>QB5LGlrzn ze?z*S8^xn)q8?YqJ@$xaXK*}iP_HR<;|TtNnw5x$O|-N#W}0=PyawYAH*;%8XA1|| zqf~_PB*iWJMMc72217eCAQ5Get?K+WGz_C;74I}xd?>jyhYpqRX!$rI+s(*kB2)Mq zIXKc>9wVZ&1tV$U@H)#+_oHd|PlAzc8R3h#3+m`>r7OQBMm#PI#?D_B$oa<6RBPU4 z6YoVi)BM73iDs8rz22%)xWu7@>-)h|!B_3fEW)8UT``~7Xg;waF-mlwlv0EhEklCb zVXhEuX{+ExFBcbQFNe46ZLgQ^_gakLt9$(Qifkdjp4(-OI*4LHwt0U`+WTkZU@qRp zMzz)&KZv3`y)~^kg+R(#OZhd`emX`XglY% zu;m{NK;iAOK*sLD(F|s7uoZOD8VTJ_p=APQ=4wL=s z`Amk!=+np*9UMboNVj%%mS_7jc*ri|`Z-!`MU>*EL=uOc_tN7<2Flhd+x2)T14i1P z(qMRGRMfjrb{f)O5JwJnrb>^Cl zgPiO~L0Q!7sln*KA5xu}oX;7HN8CWQSfQs@H(3RctI$u&$&r1ucDLll`i_4I3{)@A zuFTkFITeU9Zpbm~a;4hh1=(huIQC}4X2YC@H=-G+6K)OI-v!_sGA^<6P8NZJWnW41 zbdrz)$h=AYcT4@kCfL}8Ai6?k5Qx0D@8albC*va4A7D*zZ8_FLs94Yz$XE+Kq;Cjz z@J?o`C4{dt+P_2UNwr`6sH~9CunC>zV}+WQtEG9Z|6m*goFpR%*uPP0DDpfP<#WL} z-5bR<=;23z0q@_IV`WsAU?*W#dwD(S^%?&uA`z#=IEyuf`q8HMP|9qEEmE2^PRWO7 zO8ib8zf$72P$Sc(co1O)L93wiYw1#@0A-&90ERm9!yuEMj3S_j3Zc1FPAtTA7s@|}oj?8jpMthTji}RfvrPAV+%Rx6y6>GMNpAGNC zc#iwhmu`b4`>CvbL|0kmsBikq(Xm7{Ehdxg_K>{tf@UI4aEzO0=J*H=WT7t7!R#`6 zOO?bji^felmd7HQRApie90|~AK`kY3EYAZOz$0RE3FOMMf%+-kq`mH$Kq=__LLd_V zSOZJe6YFuSEJVdbcl5aI9$`;~75%SkK!Uk0hxnY)v*7&yMR7qYmOlRQl`z7J>>FvW z_%{ho$>l|QzB**SvSA;EFpeh@O+E0iEb_h?8n8+hZ?M26&fjY~Q5{-4--YQ!Ad7;#~PMxzj9^+ciF)A*h5QO&!)|j!gR0ZWDs4`(io`b>~oiG!K zzD^_9COK_Xa+|-DsILT{%fRAJV;q_Lh{A*MxUeIc#sT@s*kTp8nsq0VC9w*k?fItH z^a%L1D>4 zk8FcCIw&N-QFofb=xJkCw?oaWVstL=WK-8Jekdnui>o_Gl7U=H3Mw)IISS*B&s;v0 zh|1!}^8^pg0BG~Xvfr8)Y z-Fieo+Aer2z^08GVt?X0YX5V}$G}zyVE+W%)NXhF3I*H9&xo+y$o7M)b3lJK160uR z)rOFTJN9X8N?XiY5ukZ6Din-lxhkcnc}KRRWd*1VD(jb7+r~Sw*;jj3gQn_o)bB;r zPnEtZsy;$ODXQ)~rNABkl*!TM0}-L=Cqo}(ez{T>dXb(>o@YLbq}8R2&na0jRu<;R zhl~Oy{s;!a@ysrfSMPBD%x}COm1x2RV{K>UC5m+CnCR}#MJMG7?8OI;-dlq9jm+C- z?kg!?sg*P?$>we1BIdQj8pHpN=wH%B-@dWEAMqF54k1Jm{Rd3Ix!{eGx@+rvKvPCRRR9$_^w$!@5)JNEK{) zOC`%1b{FjfLdkWZiK$$nBBImWY+8*a{zoYz>Jv~!s@Ey`EFEPbBlXyblUCY>tjy(SmD^^S$qdsWPFoK zxD&z3t^Vpx@opGzR#AG6RHvAu+2(R_RjX#5zNo$teT%ugqDQpqBGJ|6^3zk%Wtze7 z?rOO?Xs&%rhn@`kN z7C+KJ17_V@YU2^$Mw;0)T{9w^riLphKR#gZ3624)0?{Fu*laMo^~8p_frq`M4t`eZ zAB|#*IIb?jbcf}Jr`1dB3vgGeMbm2W#qZ$Q;NI7WsL_W{8QEWZFUNrME4^xNgpB@2 zp>^?TxOIJ&%s2#vvDChJn5_#rM5ZZ3e7%UX6&X+zAg&x>$|m5g9FY}yL?Jb(NOENL zx1kKD`7`1h+3cK>#d#cN@Hv*eOV=)tD3R53FLnXijSZ^ z%yo+gWy%+%D5rWfcbt3_8(o1M-;ajla^)DVfZM%WuHqNW6}6yhP-!$=g%&;}J{QpP zbm<3OUI*a0&Jun+pOXmVlzpufKFwP8zUI{TK;g541)WGqbKO}V2xo29-J_^*1@T)0 z8T!rweG%C-IQbQ9#?Z^k82So*(&&KT!ig%*OwV`V{HR=aQ~^B|Ktlqu`i7eS^O^s< zHYmIlQmmjB%^D0HPUEBOL$Vsj13U>rS9pO=A(ArmKv;;lHhwSLs@&i2&P9b{h4C@CJ*oLwd3(3&<7E<*2lPP#T>;BXjw`RR5R{!NKvY7l_g` z>He7&Ek{NdHMjANV3$+UIZAV8kHNjUf8PZudJT43FUCwG#}ej{DYl{u*n8YyK}V-? z%|#q(Ewh}%b@@=AwHJ%HR|OBUxzaT6M%|WP?nw^4Pij`K!9rDVE$?4QRWfOdm|oec zFCnr+SQ%%~&*X=!W;w13;=%Jdxxo5vB3Ahc5{FT_1d&B+PeS-@9LG{nbD5f2s<~9v zHsWOZ7te*Db{hYtQIx!7LFA}H@CttGWZ_%n^k~X`2+}@tlB@Qtsx|s1Q3(c=4sq(< z)P3zrhQ)1S=s_zoXpU4HKz%TpMMptqbz`B~R`@xE7vugji9tnwSn9sH4S>qs8@*pj zt3jJWf*e=oiea~hxq--TJ|{rmc?RCfFh(#KZ!IGH%#~pVxQURH@5Qn5q8y;e-SSPW zfIxJHS4z$)8!|4oFDqgZl%=peK7>Y-?dtO8OUKtaOOMa2{Y;jh-5S|$nze5eE^Eq` zrCRX%#nFMV9^gP%&@QH-KF(0TjFFZcqc5RkYjLYR^wSEaZ7S+zL-!G~ja~d@sy~yT zjGanGJanskm=olH^Ogi>-yL>uFq2FV(rCY(WeT=YhzJhBOQ}6SRNech8gd z@1YjOk7?7#)Rmopuu@+fE*{pDbYJ9*RP-SlfyY?U#Thzbi}+kdJV)&cddpreRbTB%yRw^`6McUa#0{^nb@Jr zq0;3*lCnR~S65`qw@C9WxmCFmFeh!cq7zxjZD!pcRmwh2Eq{>35}h!-tWh$F5s8vu zGNE0$L385AfoSN&Tvy)z;%cF&S)E!hrwq~~yDJ#I4!2~VAQskMJD{f{$+rcAFp*bA z7tlk9EU)p&{Ys>3q`Dm&LYG;Y)g6{tUq_zdf~FD>g?;gz zbV~Isk!fXgTE%ZKf+6`NUMd)qI*@`o>c}c07W5c#Jqv{M+w@T_nX3o@UFCUPZR{v-;EBgKGTGW_7a_WSk7a*yH9g(~7U*q&|&o0i-eNCbYO6 zYbU#XO7v_L3-_?as5&;#;IkRs^|Z_5HLARz8tn!9cc_ibeU9U%=2TKcI>LC`-1{Ey z=KoSQ!s`A9e4t71eBC)YpS8RF^!D1K=Ae_6r=$l$Kjeha zC1}fVV6}N59p(_J^TTRKznpc7BY}8k-v z2GybFY)vnP7nS+Wm1Tt;?cuH&@iyM!82#Xi*jV$qS(aO6#r>nl%_>DjZC7RSuF&Iw zf;~{gu_+5IZOsaZ#$PHk)`h$dtKZs@0>TV85P2R-MxHtTV1YO;{1dE!29{&|LBhrD zTr%G$A8RS?&v-rS$$RjTO38p zHY+51HcJlW*-A2sJT}0^H%GUT{)|9$a&~+>o92A#vQcbzVT>k`Qa}$exvNwQQYp^pDH=4Pz;!#_;eKy z9+Jqpy3M>RBn*nYs06V*a;M-`vxD5(+LOAt-QroK=b(Of=`+ks4$~d+1JnUxh&=St zb6LY1xpIrQQ~4y-Yrl3Ox*Yek%FSQ zp{Y1rnmV5%7Z_sJo+eW+7q>+OFs4KZXx7Tz5e8-49u48}hWyHsTyo+mYsv+#mF#`k zNkp1C&-Nrb`*5&{B$yVaL_=90IV1Xm(2^I!|F-(Wv_XTG zf_~z$A^ql%JN+G*In?xC0?y*Iwf0wZgM<2q!}%5aFU=YC0!*s{rKw(lg;T{V6rRGN zy0ub?K1!zg2}6U)8Gcjf97+R;%|dQiPm#4afoj3P&fY0HZZ8E3fc#GEcTNZW#Mud5 zI5}AGzSaLgFuE{X&Qd}9eYG0ZjL0~OI=e>_|8YFMSyR8-B^Ar3m_W_+u^nwzFH?zI zBC*UCj1|Ldv-Xz^mTQA`1Dcpjte!xeMCga<@Ur@N9wuKMQ5ekWYso1rm9&s6dP zf;_Xt7_e7SOR;;4o+Xh#P<6U#R_sW8OG7!XWJIUz43FOsnCx+1drfewEpbl+_Xoc{ zgR{XktR1!AvS%S||DTwaxbx_e(jtu4TGDc zN53ZnFj%O^KMuY%4-(a(982?F4&xP|``w^Ab#z1G8iB-hs&*i8mF(4u5uGO+&P}r6 z$fFi09(ejX<*1NVpaXWUHy%~@9vt<4>bAV9fD*rr5d)SVpAJ~25Y}piVi^Vh@4+R0 znFkgWloSJ^4*g;R+n+U)x`G!JL64!Qosc*j=JuW=*`Kn9a|C}(_!Cjko2y8N_$;<} zBwyy4EYay1O{B1DM_|B;I%Q~#PaIR=#DO8kzc)twgAZ1|!7C}Mbt9!Nmfsu9M9}${ zP-ms1wWmzk15`S9_}xFign|!&$c`?xRL_ylFe^v*XWCL!Pu~YkXSKhv5_%(CsNC2E zi$6B+Yr(v_xJx9%F9*zum=&D{xoAhwoyo=w4lu|>*4_!65cy?%jhXcDXP3_rtz z=8KEZw?ZeTFp{Tmgxr8wN0UM3VKv_hXz#ec*d$5o;_~VN7=cOP_fNy%;7Jdkzz_MS zHaMh2>MG}kRK=kR&07DvAN~*}i8|eHvvsKrrAa$#s4uZv>+#Mnpvlk3ooY#&g6P%)R3{$4ORhVc8k9b*jK!?za$nr&wY@Gh zLuWogwf$kJUgL=SU+<-QhsQj7PyBoIMLC6?3`t_r5u2dI$kf-KLxg+t|45IupgevZ z9f}!~QvF^TGtTq+t(2KlpgM*sWo@bdWHEtZ9DGZ1w-%liiC|zhOl{kt;eW=e*x zN$0;v@ME_j6)M8xKhmKFGBWYoU`Mpvxf-(bX82f-ek6XS7eYg#*#q>%muUo&T${2_ zTHviuG>ih$)?KvK-MXHwTZmI3Dsi`MPfezZGV88Zc(cABM=;VCpDv%8y#G69JW8}e zp(Ze+@=WqTMW{x%3U=&wA8Sv~eSvQ8U>4&QdeD!$Jm}nzZZ^I{P59+rgNavD@K@p+ zrfmXq@T63Mw}=VpvD~DU$$v*eI_@GJcei8~3wn8vL=c4aW_*+nH-rm|Mr&C~F&$qR zFZG2G|Lf!I?D!iZF}2@`8M}(~$Y;m@;1!qiQ4*!@S? zq~*SyqrJKO_smkSGkppiW^F4;0Pl{>CON7@E?_Oq+6Rg4&ht25oYvi0WCDqQq~KN5 zEYfmz2*ePgmQaQQ36>P&5V9$;;<`|kFz2HwqbPr!ssxPgsgKZGxWk3Lmx$f)5ylfA zFMD(}G$L1ebK{F}?e^OEV!;?^?AfQXtIA0}rP`3Fui&K^F_VA3EVa2#Cf(D+3e89j zFjT5>@P~aooY!M=Z{UcahoaI$N4Yb}5kHqYV#YJ4XcUO&tIsujs=03j>1V?C2*40> zuxEYYw!A>My|c#WV6v`XjvD>aO@syswDxAuz-wel4I=&w9}3>no9dAixZ{v^vYHhg zF>7mSGc^peb_rj4D34N)4vl_={N2t^RHv<|=)oHI(&r}Wv=wU+okwg4^VLsgSw*m% zLVj2X*)#L`VG&QvO^oDlnu{C#9MKkCk5CWoPkTZ>cHG&K zzz&_L!8^&<#B|_DI%fPkPoqFQqKMT>KILCxt4yDkzqKp55~5DU*(oLtOQPO<9FW-7 zS1)ojm*pDo$eU3QCJhcvsn&3JE;bUVAc=j1S@&lqSBZ9A`XQz$K}=Bs_DjNzaUspq z6M*RIlW-gZkO6_Hqgiw3Y0_5I@%#W2di!ArZwyZLxpA{Mq&^Mx$EV&en z%vwBcvJUpTxyi;f1@`zwyA!J8Ctd{0`pMTHvKUy<-NiR}#kU=7WKZb9til0y@5;Ra z(NpP16Okh^Z1LT=f>h#zJ?`9>SRrh}(P`P?Un1Oqzud`-u8SLFZ(L74gyOPCW3Kl@ zAs^8zI+UP0=Du-?riTPXl(l;ukc3fc!|0QPg5e{J{G-jQ;aKFAn3!>$3S~&- zG%u3iI4|h>#*x47P1~44j9Dw&7lyOK*SfEM0m{Hu$BaF20}_R7Ql~5P?0=D-!l2NP z6mo)SzmZt~{wsW|WAGdMAj6_tVDY77xpNh~AYQ|TFiXedg#D_8CpSdzZKsSpyq>sPgTl$!|3;K{^ zmxO!52W(mRnVKbig5kEBC7D6|!9H2DBx`E;Uo}gNi88<8Ki4ej`@QfZJl`X=2O`br z0}ROv&tdeTWAGkU+Z>+Y7%%jZ83>56Gu}3LsrnYH{ z?DL0Cp}uOoNbKtyet%V88ft3)u!5Dp9>+~BpZp=*9*EBDmv|P7@AabD;A?sm9P3X0 zdmy@`KTj$>v*sug-FunuCNMo|uXjHnB5@Bj_s0QwWS<$XqmpH-a6jj3TGg|X&|)3A zp=Tu8=2S!N+1<6DEwwXrYEL}O@wKjy@T&e&;pX0DhwHLOb(ih>Z*swdP*z!k^sae} zq>?D96Zz5Xog)6gN3p6gqko284(?x+ya5h$?k8%M3IC_pm);&^h2=QLIv;!5fwHG$ z`oP2bp#)O+&2dt?t=7fUpEr6t{#nl_lhF!;V{diPZcgT{Tkt^zE{vxk5+FBdf8L3h z&2H->-1b(9nTu=^`COz6)r~hL!jqi!M{f6QhC0?^nUkMtH8fhcIE5CKr|O;z9T+Aa zVxVt_CGkGc2)#N~rkJsuPZ?HROl<5CnT#~?b9=;8*pkG(xOn&ZeN|^6sY}#J7j5Gt z64d)x`g4GMUZ>zJ`>Q(}G>&frZ*=k(qe-?%M#9ZF`p3^oheyRvRmC(R)zj1vU)qDX zQlHF+N9vT3O^zHJWBA}3MwbB+{uI2RyNx?#%>=8xT5+y2#<(Ayl@u2As!!@-dZ{FS zP}k@F^2;iDSL27mADlxw#y=<`sPJ>Tk)D(}dQzU)+nCfE({Ph-JlB104|y5xCj%l` zOlvarm4s3VQ2JC8VG6mYfzjh$r93ZJI6keCTF65g_%Kox$BY+`*YoDy)}#LL!!hGu zB*;G{(Q=Ct5S1oqR6)j8ig? zSlFrT#t(J$KpkDFqfaYpZtTlCaX&*smC1!B*yd6$(Gc@_X|OcAX&Z6W*x6I> z*BuF>#_vim0GTgm=*8q0ti#29w{+rsjc1p9mLfN6V}kteDBN%-uVW>*rIGS@op}_Q zHIMw$1TZ6qhX4LX2|8OA(KLo3#b+Hw`C|1KGim=F@e!Vm9@%`XRr&<3W$^p&4 z@+qdbh0eGW;k%S5KVSpr6Y|tLwD<0P8wG|lm_DWJwl-(fdXeFzy|f3rndMcB&TSR{2m#;<&H6Z-!KvEoAr9TFsAS= z9MdUI$y35%fI`rS-2!0+Qv?uciU(v<%A_TCF*9ntL$pG-nq`yQ4K$+*{E3(w@yW=J&BC-HLmdnGdXVIoeV6)4ep<`4S zy(ziU2d^iTJASW{V9QQ}m(H{8 z&y^)cWZTG1TL)y_pCdSDm*3-$KM#kjYgcv#)rfeSXL~QDQ(MYgL^pa=pCG7_xJwsO zRtVK2iMl2J!XZ^j?CiMQx$C^jG(qL9j{i2Dw`UFCPUlratv;C=ZjXo4c~uSO3h~TC zO0_yBgUffsFDDD{F%9q{sY5#D= z2D8@lJyN=@l!HW*O8oOFuP~V20RHZ|T9}@zyxk(a*x~-?Nf~f@Z!~K~VN_3N23eHw zdl!Adw~fCtdJFmv8{`r!5IN9f*{Gka5Jdr$({i59m0TW=jy|7m)SS3e*6>Zb#z#LC znlr@@n;%->k<_J)bO5?uJD7@soQYDsO%?hfg_KN$qAA0vFB7xGEC0cnaa*65(R_@C zZulYhXRS)={Xgn@`2*dPN04a*>{zO;@O`{TMG5(rxYsE;`cqgvm>VVKc!nOT*XIv! zz1O9r+(?#i(Ht`-dR4`rX4>%Y;`Jr&@adixB~DpZsPP~fg9YfJX?B?42(B2%4yZdV z;)ZyK!V-5~i;M}3FzcVEQf_tixL!bp4>TDXSJ5O`j#ysep#mDdGuv&1!ILd((&OON zPf1t%ZI?O(D9*nQWH`Y6A8<&)CUmK;8t3{X?s5OLS~UUEgf8tY_2aXoC&zErihxCz zXjUcOQRCBdC#R2R|4Dg!4}Ma!y-jRpy2kL|QmvY`!prD-mQWA;^T&`%#QJF@XcXH@ zb)Y%*X#w*Krk=p=9O^^|p6O~{24<=1L+#zURH~}Sq@kEmm#XJ5Jw}tR$Bb*ebma$4 zKOgy8XG=f1AHi<@qhY>qsT}TbOk;_AVMLzyxBCBM64lv-+_PGle6R4{#wq`V|r_UDmp z^rb7XN}lYLf1%^|z7c8h*NjIdCHE@aB_*E;cL+Iw-*WsACx4KIoAK=8?^{LB2K%=n zU6J<=dZtY7PC+TWXUf>_l#_a=3{Izn9!l|eg37hegm4ksjC-kb_}SZn!yO+^O?1$g z4CN9;n=hAqLv_BRyYu0mz8RpaLAHi+)zE(2x3;++L=?FL-r(sz1Kg?TrHK9`>(S|J zsmy3GBR?WXps1y?e@h_Q5?*B4Xe+h)du3XDRd)v5Mjj!<`P~@`kC@?G-5D^OQ#Gjj zAbM2aM?_fku>Pdl_wdr1Y(;4xJK>7oO_^feQAP(49kkHs0HA94an>-#mNne0U4-y6 z*&5&?Fp&bL%-`zNG;@3&7O*!2GMX!o+Zf=z=>8ij3$W$fmnF!8mr195m|sM8N67Qq zH^}pkZ;hX)H^?*O8|3Mbqruno=Xvr3i=Rzr!#N#~Qp??+z^*OtbkX(L7vCHL7x92j|V?9=f8%_U8N-pkB?#ML*RLr zya*2P_|N=XmtM{C@g?xgmv+rIZwV{0`w`Y~pKp{)$tS+Ht|x?$er>LXZ;&f|%h%Nt z4t{NpZ+GV~b83hA1=pF!xM)ds)50UdQxVTlF?6=}z52Z2p))*+tK&zdOF__Pqvyg$<~C$jPxVF zrq~oQ>$()upy3>?@~E{Ld5^drSzbLtmX_XG{&9pXzwVtyRPs57^=fEo?<`_6cW9QG zy|V<4kY!x&ET{CyB6Q?oMMt{v-Ae6P0ok$CdX;XejazoK-szhK)4w8J4v$}z{?ON? zFZr7EnO~DW{%g{6NDoBfxhc4s%RAHbK%+$O@w&3kzGA!^z9xO;*QD2fWqSCgFK-*u zq%ZAP`0TGp%Q18A=E^latauiOX;~_8N2jrL;EhJ}gXssX;qf{IXLt-D7HY0&Kg$Y* z|A}Uu+tWXI84k#>Z#jTRZh27Xl^*`cI6~oa=1v(bS9VpGk`Y}4mN71Y<=|S^oXAeS ze^kNxUB?4R;XR#gy!b2-)+R)pT!gcC*TS)*3|JOD%W+c~>RVcWE^;;u zgm~}DJ{KAkGjvTXRD&$NJl@Mq*c;^9lDk z%l3(6vwE`qa!cF@6(&(^@0ADdHMybVju;)@$ooj!N1AolFdlJIFY*$P<0~_B`m3W6 zPH&@^9n%$wL$^s!w#W#gcV>h?^YUjYE+ptjEt-YKC%96 zJ%FM;en>!!$o76_-5ypjO(LI>d~$pdPl$*1-LB4Moca9E!J&FQ?UtqxS^x50%{M6& z-c0M&gCpB7GV8=4N6I5V>p>Yp^$T6wqdv3kTsBa^&Yx`glOum}*sa;!zMh ziC0nYo&NA{z&$hkJ3YPJ->nidQnp$=nC@MV+Ztb`S>CcYmI?)nTdS99TvGN1s=gpZ zE9hK;&}9aq$9_Q!m4f!v?4ZpHm(eOD*`U}t-!y0VFFmJF;opVe-^_0Olig16ugvaJ zT*DarS7Z}}b!aF{HvhOU&#gtPG87gb$}a?+6V!<%P`n9z#JuZ`fY`nXbTU7&9tjp; z|Juqm8BWnZ(zrO&tXt-xgpwCZ0fmo;Kh2F zS_r&A;i^(Wm&N z*BkqlvT8xouc-BFs*?6DYL=!iO4VvA3-sA33nQ`X+1siBF+c(0RHVo=k+qBABU{u< zGT0g72HacuLe4l}koVYaa%%(g3X_`|r(HU@6C zF>;6i+JBQusm20`(?E-vR5J%4E&zxN0pb#>nOsWF$rgX6PUFuNGx_tqIsCb90e@~? z$R8mlPt?$HkEWP)m4eBC>(YZ()TI>Z_{{DdUeOnJpL72|k(c@3l)n7-|LDtC(3hJ3 zqc8Ek|3_c`e@S1I0WepW{i^$+r1mhXDvALy@gIx4ezHGtwB;OaMfPxEz1uIs1fJ;P zd26mSFM*estS^!6sT}SufzO-FrQ{@dy{UzK%jP*AZm1O2hyQo_!@sv|SRZ*R>~m=) zvd5ozP*uO4s-I18bs~|J*K1AjP?)~rOm&cVm-93nE6 z<&nYqxGVx<8*)R&X+k;Nuz@|9HX?V@+k6Rg2MK@#b?hkC*>BYCgHQ3@uI?aT_J#rKA4DX?jKW&f9HDea$L zVEJ*-876z2z>^yM@lcwfXb3t-Q@cbX?RhrwxaFKqHzccohhM-WDl3dd`c1q@g_K>S z01W9PjS&lq^)}L8Q9ro(d{l0{cH1)R+XSOa)ag z0d*#WI`q|^$~DB%!X`v^mr|JjL6HBJic=V(6J+llpSYK7mdb{AG3S!f#4AKFyE5Wd zx<1LDc#IeZ#Q?w*X)EynF+fm;+L|T3(6*lnnf8#-it^nhxk@{ZoQ34fC$bMY^WzsO z7&87ez6fZ)5@(tf&dBYc#u>pbjWhBhM;ZrmEWrV$GT6TzaO9+LfOVyj1KVX+;G`0o z)%58S+k*W!kRa#;`Z1Nd0D}x{+NzBBfu;=1!x>9(N;QNFu3K?_&Uq7j*~?%VC}44J zffc+&gT-4P8V+1ZJxjw(;Vrp|e|mrwQ1=1RvZYH3YdrW0%1AwurnG)i(!+)ZT}5@>XeJjd!hcM_{#2AHbK{tu5RA{o8|cSt&5| zTeAcGy-+S8kL$A>urKDv=o|Oo&x*UTqV_;tOL(Z*i54|q937G^t|p3F19dNlcrW9M zE(_a&((xaMeo(tHbTgN0JT)z!*YNq>?$7CbPVN3I=d-l?a~z*V-JhrMc~bZ1a6Sij zfBI|DOuP(q0Zeqlc8b;Uw)MfMpt%mzX$%r`)>B z!vH_MgA8Stl|6LNBmm2Ul@j2Pu86N43>iqHgFGtJ=Ir zp`-HZQhAyW4&=ZN%ig8(a-4&pErpyK0cT`R>9KbRn1<;>Mz3EX#N@k_o=K#^8{Y75; zkTTkG&q}w7S_o}%6#HIqcljgg#%<{A3k0@v7)tkFA>CHWEM-tm)vd^EcwVR zSh&qBSn#r0FsH>VnE7|JVA^lZ0_z^Lpmdp(*eZpU^@#TCj?#6kbgQURh)elZ7J;5P zJiy*;En6#{1C?*NK~_l*R8DM59o$p&NL!0yL?9MrqAt5^m#bPl(#Tew^S?Q=4%LoK z_u(U(ne7-gdzFz&i2^y^9JU-b*clAg`AgnrsmS?do{Tz(i~Ozfy=<+Fqb+i;KAdy(~^RdWDh7pTVuHDWgC ziH?q#+Z^Q>gW5$!J#-vOt(U%$LC}h!?UYO|fnOa_C|Sh=$CfZ9uM&bFz8u*pQ|1sN zKfhp%JDj3kL26K$%)lmHgshZE69n|&3l0qTtrB^gsF+u@rjr!SNGsSJ)s%bsEMNSo zSYui`Ddz}xQTh#9{mChkxFA6hro7~Gsd%G3F2FA@`%U5}G}JLJq1L^v{SYOX<*l}H5uYgWJ0s2{ z5ZRA!^hapO8EUH1;R)^o7;va3ZW^aC2yuM8uH4CW-$4|N-z9FSB>UAk^ZDonRO5{V zf8C8(N<{Y0F1N4siKp=txVu%=gveqc8!7oW+52D&iK@Oh6F!iE9w<@f-8VAuFD2ROlT7Aa6Ypc$<>DKG!$6K%H@A4aLe z);rEXl#-&Di>KUy;Bd@SPrO}G0CfX~Dmau1JYtRs2*vTaC(KVK_qO?H8-Sa2AJP@a zh&&IJ-$3PO6EEkOwGBk>ZIib!%-W|2%bP?w@}O+Cd*D0(A!d>5aCblkH54&veg(Zo zR%Y%F&U5x23>N;|ASY$~?&mz8ZABl?dssT6Vqy~G{0MF@T!^Vy*{WtFxNAmB*@A=a zZM<7%WmK^5?r{h4#v}$0Z+|Q=ti;5sweCvkkyG;SbEvC{I$cQ%iDsSnK<_jjBaDCK zDSYVp#4h_`;(Q^jYN_)4ib6B;79C&jJ5NQ3vQsMl?$~?5(6_(qx?%=4WsEaN~t?nzx=1XpQOAg1yhVc^rpONxafgjES61xa62wbB{;L@ z_G6Mqp@9{>8vW_=ygA40Wc-+43zFz6#ne6rJ5+#H7$|-LO|+LAANxafChs96#+^l+Gj#e#vhvN^o9Lb_vP+*G2Bhz6wlYDjx{Xp_j#+y^sus4$DLID> zT>Gu|m4bG4aBJWV+LV%^XYcm69^T>(;*=|{K=FZ);nx2~mhCU|)V{`cA^VPO6GA0| ze9MJa(0M#hAQyC=!rM1(EL$s!pl!g2e>^h`n^uImf)EYhs0E%iolM!H=4J0DnR9ms zIpd$PCWQX&cHIjynA&SQ1eI#VUec|?yrA(6%5jaUuzMZaAn}Jua!Sr4pWx*vD#4y* zDP*eC$S0Ch{IM)x9%902If+eYQ-SMHRb4Y?#r5J}C78*ovSW>9B;k_J-sd_zAdCj- zdt%TaS5MBkxAs75osup5L|*i}SJHqpbS+=;5b1#@Zw-fXZ=Iieb70N2H{ZJGw%pmQ zvR~%?M1aHlCN=8!zPx&V-M@)B1K6|>KdaH|fkN-+wv??F`%8J|?)v8IAUARW%-e+a zhM$$SboD7KXfL-h27UD9f|s!miGHWB+-|8K7G7@^?8T*)6}@7hXuQsQpTT&`V!iKb zP9y7SzkpptZHXX9{6zrlUWIv>Gwvuoq<;JqZInUPspvhs0cEG>E=Tdzf=UX5oRSY> zYyu@rm*A1T3fRYg!uYkfF&5^=#WH_!A*+q&$$*G!Bu>TjGDwW~Ks=xO09j($cS zBeXP?IQQomZ0ROq#)J>`Rv0r%*R$u!fP1xjqO>d9vL?p-b&O%;WWAJk*(C!A_GWL; z7krk(jo9T1Q>@RY3q}Dd#r?pq#hSTM?~ypAN22g^v1Y;M?!sdZNmmRF@a|Cj9uDpB zt$K##oG1+6sf}mI5J2bfJRzdZp*#>7Bao_f&@w!q5nQZ-Dei;8<#5U#aXGPxw`gDY z|F~XVSee`1|47O8yMUQGZ+^R1uDc|cVzuPF*WJg_H^1GZ zbTEwl3`IdH zIA723?hw~5?(LMY=I$@E*QaWE6-@~A=?|+5{(Z0eSF*#uS6zKL|9;J3af*MBH5YiD z(#UfD$ZlXWAMBoR#CH3rd&x^Pg$)!Pe%D*5F!eQZf;y8L5v=?Lt?S(nGSWIQfPi27#+fA9Ey+mcPA{XTO zLV3ELOr1%2x@;kn<>2lWAqED`umb5Zaf}!^)8~etWTCPGPQYAiHH6l(Ih9OAQj}?t z41)h&BH6cj(%4w3GQgkVs5VyNo2hb)y_Z;FSnxw&JU}>T=Soxl00-y=WC_}%?;Q)?Rzu(kb(L+_eC<|gO|@SbaZ-Nm*ej~K zt!497`{I)Lsfn(VM)TrVTS&E=Q4Kems=~~h{q2rSn}XJ-1!}~u`X~V80gfgj zz;D_c30)JT+&LqvTjkTEKCPyM?wIW1k@i@vDoj&6TVY<)o}e_Sjfh>`^T*vl>}*h0 z{Udqwqd%6sv!RvUI`1Rhv#Rq0d42NAGNsvXhA&3Ckip&D%_J4$Xa}pgbGls%uiD`z zE;1b2(6@FXbWDpg30I6#uhaMmmFU{d7LiEEHt$wyG~bA(`5d>!Z&1{|PTe6sZ!=rq z26wof95ZH-I_{o){9g~J(!n_RcSR} z6s3GPXPbKl3nlOsu6dyIZShYc&V&)$%{(ZKnahm%URU{g>^RU<+UFzpeL8=;mbNO^ zall^luj9ykys%%7zd*gu>(#+;AGy46ittb(MD+GoWYW*z4}44MLZ!KIFi zKNF9YP_anTGFNQ-*uCMJ-GiCwM(Q;vQq15W_wWu z#j87uPF}(OjXDU-1crqck!cjEdt__1TgwyoNwSZ3>hnY1GO~aS(FcfKfCLLi{Cz*% z26O3p3E+~WG)rGO-%JuK^(RujDg4=9`&^-w(x^UqJk2cM2Ow73u!GjS`Q!c?;fUk5 zBN0Hj2J|ut_}QMILOmKc_HQQY8>(r3g zT2SXaHj)u-_?$qaH`32K=d`UZnCq-H>k;A16>fCCLL1lF@s@fA&+u}^JC460l1!aI znbvKLo%`np;hE0l7RG{WNIB(91mzDY7U5_mw;qoJ98NHjDE^&{s%{Y-U*g@(wg&ckCTnY3B%Lr^It`XbNAz{r#Zr=Z)QVqtUZl=<{w>_xky|#-JbE!pC%Na{uBY0Vt z+h#NebZbp)demthL0O}5(Ve)8E3Ol6sS7FMo;59B;xX9f>PY4DFE>x1|7&imSjR2x z#qKGzhH{4vx4bPHy{wBEafC*P5xN5jkjv#dt0Ux*5EOey(@jRqN-co6JY9oEq*{TL zoDIte=C}JRqFZ@TNJi*nzrN|uJesaZ_%Un_Bc3iF3%MV>tS+qb7KvIPQJa3#)sGD6 zxh0Y*`s-T54jKT(X3zMV|}oy2lD%`2n z+dB%hnA)F2?H3;1pIWWt3$)iqBCAFZ=U(-YHf_?{{)VqClfmGAvCF^u<}e8Kl1EED zwnNA=&XO4{?Ao>8rrf%`AYH#Cl8!Hqq~|VLUUGIAnd{0H09gVckW6hCvre)TRCw7& z_Z*F(y~dq3Ab$@?UR$DV>t&0zRF9)-Owjbqxf0I?y5+=ouFD;)j_uQGfPa7@k4At^ zv1H$GmA%h(PlsBaxf}$|#JPUuHTM@!Nm+4i-o$j(sgW^r7sW1yO&>+jcp}Q+Z7wpb zLvd$ui38aCz%H_81ONvKNI1u1lBDpHD5Kc8`#Rkh;KD==!Q!!!%9JZiLdFQ(BXIq5wW8pl`Z0| z@gFkLf1|~yb3A;Q^5SaaOCn>&UPr3Ye8bNL7-Fs6txLP}UbdF4a}Omg*=91tUkA(R zeqZa2mxq40LbX!JWHDeo+Q0xWKbuxo{*tHG`}yO3kIRYt52xflwCh8Z5B}oCU(Ju4 z&nicXC0A~rZx~1fks|`BibSncIYuVuZmo&ZdY;HzZl09*q!#`QdQp=jJu#D7XFJLq z8@avcnXN`P8Qix_K%Vsmb}du+skOh1Vx&6~-Cm&? zLQ#0E%!1NUO}}|0g~fO+eb+5eCXbk~7_#yy&5keW;h1ZD2}(ozwkKh_P?SBigL~zn zg$?mHYAQdoQj>`Ur!|F5{tovDxUG57v@78Ssk*ju=k-TKr!kppmo!uz2#D;MlCS}7 z!T2~6Dwy1*cIxa8;Wg(+(V5#@4M>eW@N?rrmR;mHvK|-S$ek*kyuZgY2vF~gz8nQ+D+thDK zi8@JNqYSm5T<6T-+Mi@uDd?^*IDt?&++&PL-QH8+%h&eCaOT3bq0AF7(D+Bnx>&eH zWtmzCWZ{O}%Oo3@gdf#_Iq?T74KGL+M)jQ-Bby5|jfV7a{TZa) zM=6Y;RF!GJ;x3=Bn*Ls9#0!>Zxal8)q!xYurFoIzsL4ECS~j|8kXE7OXpjIMvDYZB z;qFni(ebz4ACjqObFky~$2IvHxa}xBFfZIucn}vt&0kEto%0RBf?2Vx^I^wu((2-# z2~LAPV5^H&$Urfiml|ZjgvCQ-fuW)J!PGQ>n)3b3nXa13wi>Ih4F@G^$*0D63kn9o zZ}4*}qKNZ|uvD=wu`4vI#0V#5|K;aG(c}zW<=m2O`ZP6NOaDyMRqANa^kJrHKc{JT zZUM@9zw%6b<Gt&MhC?N60K%(I_TTd&c_&?gj2qOm4c_c&xysmMUvnRGZWZ2Nmr1gbQ<&%`*ybAQ_sn^4aNrVW6x1vrJf(2Q`h z%m{l68fZI`Zkoi8mD2UFiRJ1qFQw$CrDteqS18`8Y0|AeGcv;xEhbZJNVL;W1;SvW zK-|`Z4sSi3t#R%YyCuSomD(TiEa2f*s*o234Wn!7Ga43h7PAo)#i`Ton3Vsbo@wtD z;Wtv*2^AjAm+Tg@!Ai-LrBcPp;L~X)>6cy5oAfS8+7rFOZ*Kn10>Fm3or)sv6x{}M z&h6di@`6jJ`sx%#^aUXzQrQu;YH-0U`X(uzMTfu2?uLKvov^vY*s2$dEy+UAGfPls z(KkrZKjAA_SRVd^M5QZRynC^vJldr7@ilVz>*EM4i|%;z;%2(~)0FvYII7(wj_Oqb zvgSjypsNd{P}XlZDz0J%me#$s7$G8Dulne- zfWdA*<4#APp%nY^)<()8yN+U$@4ZS!zs?=GI$Kod!JF-GsQ%X^uj^mE>y%lVEL z_p6mtTUD(Yt)HpEHupuCq*nvJ{30`82R*!x6Y@ksQnbe$0AQQ#9+VTGuZ54IYzt279ir3 zu=&b7ZEvfqEL#=dp6M7ftN8kp#D&v0v9*zo(d4ajP%=e|?T<1YoZEDUc4s)!50zdiSN9G#qvMNS7)DiuAcW}#xzA7qRyfM+b&u@8~HL}uJ{-_>+5)jH&6{y zS@Cjm;<0im_ya0Lp^keG3Pd`bF-xd}((yH%`SekX<0GZ?$u4qeD#-A=o>#Kz4CY50 zavyH%S#zp?YBKRSs8wx#Y{#Ala_Jz{PyY_E^xSjmw@m$s$MN3v)5nu;{C#tuSTOug z-_WPa`O~NQ2|2i|)Ifb7xBK_i8?)e9DcytM9l87WXZw8b)c0NdNg)h=lZu5Uc5Unq znz>dR6}Me<_d;xKoQLB8(`4hYX;mO5mZAzW_hMmA~d_On731An1rC;;j z8b#6a*uaC&#y{XJa;4f@&m$#b)vT6Epc$9eHoNEya=P{U&X^DD&I`5v2btV4L5Uyr zDRGZqV&jXHI4t=7ldt&xMXlfBt$n@+EjFtBrr`U}&G*`k6>ZWM+yg+(`uunQbByUy zR6>H$VaVR^>^tw*MC3eG#X8%n_(`q9!J-=+xUg3ux1If1^}BqW_l5FYf2@{Q=o2}% zc%nM_8k(KU(aS{AQ}TjLGq(`0dNH}(r4Pwj%t|%V5;OlTYGk>Ml>i-zK}8fI&K!wi z=nd9y#}43UW~qEyd29EEw{O{pt4tMC*}RvS_h;Ddp`@_4MeNhA_#;}JcK1x?@PNpA zwunU&m4cCo47`p#wKu~+Kf@uUw6+MkKhzkU#^%Tt#jOJGg;$^;6szWN>|5&M^XHIb ztkE&rt7c)|7*!Uj{5W<_1aGQY`&!Eg2oxJobrSIvA0l(BnF*pXU0c&#h{pBz5 z|Im%Ht?ShHb0TQOuHx0HsVL+=;6H%1-ZD)s4LGC`vd?`wSYkVip69X2q~i3kn{kni zx>=FMyZm+7J7Ll8{&?YwO^)zI+~*}*hVF%{cux~>N^dE5`)~S~^#gl<+jsHDd4&%( z&avYRUXD1~;AKh2k(CHPpNNyt`mN`Y)+33mFD|qz^J0?Ssl)ROS#dicEY`*9w zvg)}MeMm&=8hUB^o_U@HfaCAnwDN)5$mq(TNJqKM9QYzx?*ZTb&HM@cJ)NQe!)D4TtO#>lQ#S{qoK*dEN6&&iD&GFZEI2_*m@c-(eIv za_maAg$W6b2Lj%*A1zc&RAZdBYPxZ<9M*LIL7~{0HTJRBm~NkVt@$~k{R#NmC{_da zWaI?Yr1&hMf|3c|*y3|xSv~7DB=1MY&W6U_33%)G{B4i>*Q8N$zfr?V?EfQT!z6dd z*i7czw$2IAN~RZiIeMo*kWGIl(Fpy)_9`N`pF{Z=8v;8N+T4Tao3E+g$s9C-g1brs z3_aWjLhX*0qu%F(Ki2KF_Lh3v6{n;PPSn@H`8M&>3FpL~gnPZ{U!yMz#kyA%baVD( z=;Map5$m`~JMPqmn?}hspIn_Q%cz@-A&lj4l=H~s-uITCsl`3+MlgBogkb+<(tyW( z{cM)`^-aqUpt6;l1vS$r%d- z&#(9e5r@kX@mk~RE#~6RyvQMKiOoncmkuv+WCe^rna#08Iarmn{C4?Fl2a?IfoMNx z0;UCziQs0sVzd2kS`507r2Ojfq*9z@GA4Ffu_F^Z_luv1LIRdXw-^uFXnM#HZ(lwWPlP$Q<3rALd;f$- z^uD)y@9~aN;z{of!#sRYZ`N}#C+lQ;JeXRt{rH~$(Msl%m~+(?kAGf~QJ(artcden z7}sMBq8%Nr#|+)bb1pozbrvpit^$%I{z+uMbJCX{i}p++RQ}n>7AR3GSKlx+_#S_= z&r+pFislwOG2MRg)@SQnL$!mbic8THxfD&(i3bHsyyH0SVNlL+w48eq+Kk~bU9aKkN-pGfa=bb*NmRvEu-CMz6tp{-RV@zUG%_>9Q;X;w-{)o&f5I3sk_*mH}usFjoDN=^^`1fa-<3hIU9Da-SgmhXl zh$r*Jm`ls5u8#?!V8BW$;!~J=ib3vpr|@;FYYfoL{085m4v`Ak-G=($8EEm=$ajxE zUHFY%3QVKycWTN%3Rk|Lt~nxPKX0Aw!U~6?qHPdrhO7N~Jq@B4d*ksy9(68eZLULP z(9W@PNXZSHgpHNJMTC?t0?ET9{s2hk%GmnK&DQ+Yj331&F^THR+f)wMFO@iNyQ$pLRCy?)g7w=(T`hZZ(=Kr|3-5BMy_b=rlb^^En4a1T7t__r!_& z@h#8mosZC$#in0uM(%C3#@XNGj_ zQzLorxGTPu5322Uu5{vd%OIqwZ;(lRR%E3PqAqK}J_P&XB3S#p?6L%3{OpUEp zS9(UC=g<*|sVZD>bM;EJ4(z{fGlPi}yiC+*&o;e|cAh<3)6M$_{YbTWS5s_q1tZ?a zB9wR++Jh$Mc46+|)8rPr{^2^ic5#hef1i~!%Jjr%L%5kV%nj$c0Xh?nV6V^qKCNxV z7*b2=R3tIC3mU@cY1I@BWDkyoi)w4T+yfp0MBgZQHUdFgU>JvT5#>fJb{^UyTHDn7={-bL@UehMz-pn77nf4s7;FYr+;GQuxlG~NDgu~krQ|t zLa~D)&g2H}R9nZGIHy#eHN;AO%4BnQovL<*S)@bu$e^{igMtM;9G-|T0CH5r9i?u| zDdGoKasZvSZvWWK@LE2r(FIJQ_ijYD>O!kZ8;w3bcGV{2}2j2DQY1cbfXeeSQC2yaL1 z)U{yCUCV34Y1XsCF{f)vj>+OPT_f`qMqSR2*e3RkJ0F+Y>7AjI>AWd|?*_V>c$a(c zGODp(>kOUrqiaI$wW_q&WUI3h)U=hFnmIk|>)WkmgBw0OgRMtqwf`9VRJK^%mWxlI zvUP+ebW}4Sjwxg<%TKtbSL5@9LqGoCQe|v?2t+-~mOu36$G^9d=Nr7%gV$yS?1?xg z6a8;;XG#BT{7<-u!hD^7CHGfLA|ESxl!0w>gDfJ$ybi3B zlZH?nGu^c%c%!nDn^fvPRKcu_KkQ7tJ+<8~@$d7BIHvx^oOF0CA=0_qX|%StM_j z$mOgMdW}z#TXzyeA#SJZ+Rcr!`1Cz&%m~97vpVOd;eDo!na1C4Qh@ZG{Q>H%T>#V} zuLLdvS{8toB0V~j8M2?S9L#NMIP+vHxf9;y9{V7KiN`_s@A+t2+@Hg`q2ivy-P?Ie zjQLvBe#J^XKy@sqk@aqU`ieqi!J1J=%CM)@xAr9G+9r+l4}W7i6k96FV4MB~hgSmH z1`tEoGmG7#KhWDB14;kR&AAho{(%6&Fxe%}+=pQ^ZCZTi2y=B`|0=KH4~- z&n+b+c*UkBgs@ji*&(FX-E?6jadQdE-*9G4blN`<;$A5Y#b3i-pL%09tk>1nl$HPL zvTLPbn5~mn4OFa?SK89(DoNZCxgCigKcDcq}qIP-~@+u9@L2N!e&NhpMyN?bx zn3A+Kn$X?Q^e;}%!`QIKziYNpV$xIuCU!79O%fYM;EhSbf7`vZ6s=56*(iTpd_A1d zeBbQ`&F%w#^bxGBPNWXWVvxKF@D!UJQp7GSb5A{_Kc>Sp zf%G6;Z(%k#lZ#P0{K(+hY>jyW$;aS{Zg6~dajNa6Gjljz8=dw_7RM5pM~7laJ8!$c zg4u7ULmWNx^;mPtrnA7QO*OYAJgcDr*>tb{#1ktj2G#}@97{p@u_;iFJy2MkQNDdJf5#x`~K zB(1QiO&$2nFqJ0^H_TyGd`xQ_t-7I;0>W4o8)z*ftbP30>@agFCor^%Il7PD#!w@C zI894o+K97n;0daFEt>c|Z`P1-M;-vR*E8%VMbne7<=waNyXW9sz%=1lhED-3 zYn$urZGn&Uy469+o^|R|q~*f%!{=U57rjs|*(e9vioK(t8&Hyu`NT^?lfll)$Cva} zkzfO-mD%jybT4fj&!L}QYYgdwFY(sa_zwR~m#lXGh{I&h)}WTjW`wy2Nz{pCUT4o` zQ*qhGs15B4(jU3F5pE;OL4$};i^yoYPG+Dg5~e2F?|))EtlJ%P_!wdP61SFzprUiAsdV9oEsbdEm{J1HyqE6u)ib2Y8O ztAQcp&Uj4Q2`hC5*|G~)V&}<7o2BHkZv7hRV(?V3@llHV-f&Vf?zfIk;(EgM30AU& zZ7@frxHNQiuKkVdKoj2??oy@kybI?Y;X6SrwPSStquBY zCEuYAr&-vMU%HbPOl*l*K~eBlmr@w%tvEcdQf)-I9Vl!ychuM);?WivZlzwKc-T3w z(C%*E$<)rX=3h>V&}jT|!cMr@>f#lyGQvtKTs%ob%pNUI={WI^HY>N4c!sW;igkFT#xZqFaB5Z??bpQgkm3nW;cBakxi&J>)lgL& zijRO>R!t&W00pX|R`O_mE7~%qBvQU=$Nzs-&#$A-+)`;kQWwyMKX%eRJTC~Hr5eCG z`x*Dc4*h=MUiCfkai5Hv!kuU97<90)GV7scgL_X(O!Bggc+YOedlnDcI3Bcf@u1b< zT912&(>ha_JJYKv9)dkYg5OE{1wKtPd}^h``8j6%Xu4U;el)$bLEl*-CVdSI2km>> zmxP_`hI+?PF?cWWjAstC;k}MHCA!g+H%bWg=6C;L+V`X$=Hu|Xye@AbMH_C+3$+~k zqMVgC@ajEbs{3}Cy--7JJ>ma)gGlZ>2-yMfB*#+6`Bv&K^OPS&ox+o~?8buXhRhXc zTKKst*vZEa=jEE%LHv!!O87fFwhw=a`FepV6E3WRYTrc1P*q_i&%%?W>QpOvu71BM z2G~TX2ffr;$^X*tS-9@&w;nYyT!7I}?PI_wy3k66%+mls+YUw=ZXC$@aY&hGn!KXr z8P-5wPUiKhmJR0hY5(grEzg_RR{u5LveCRQ@n2`RY%;I9SIdWfIY6|$N}`u0Ez2!V zp31Y&8@*=I4LNUud>DWc!Nh}$mH0z)LXgs#DkOn14>@U#0Xd5KvA6Y^N9~*QE7Qux z$DP7l;#X7~3{Yq4Ns>gRwH2F8o5%9PWolLmAp=rds1{N0B!U)^SjmQ*T*z4qwL6|k zMkKAISRZcDJu{sGWsT;^K4EpqnQwLt{xymJV#^auExQdzQ=*V(Vi(le=8QmqhDc&H zT%cLfR*k)|fgksV-v}{&CLcdkUE}z99Fqrt;4XQ6smW3v;uZ|z7r zf+O{aaAtKl@kO3>tLzZ05u^1}U@jrf7<5MR44!;u;N!J2Ek@(D^C$6>!i+It=*GEH zIus!27EfVA*x+gaK-hfmar2%I-sgEMd1o{Y*Yk#;_tMZZxB3jLH-bElfuhD)s6oqX z16k4p`#@=AlCM*ihBTO2@>%o~lC;7nzTl!&a-a7in1IjdtpMq#IZxLJUqA_-pS8HNlI zUB*Kn90f##ej$A=1a!1`>RE<>V&BJz+;gNMC(#VeE)*B0_lc_2A^(DJ?%sTr96g+j zY;F-uD4~v*x;H;JsK24gjOo{2#xDZ&5Z#-(+>=OfRtO6K9Gr2Kl z4OwRsS#DIZmDCj{&VZmtKr19i(idU8OSS3INvXChW(!h6E5nEKakca-DRqFrs?4(7 z92#O;Tc|Ib3#nr_?cK@fgq;Dk&UDZeww{!5W6}~|Qu-6M;H(g$2=%u6TnZ*oG||Ck z#!Q!pb2uCN*W6=%ttsUv*|@*F$_B5_e$jQ%Oa$o~(A{Sp^r-n*pSKkRrLF>T0a%`% zSqs%^E+VyG#0O;iRJ2W5WFxi6B0h zU3=LbnoBTa}q%Fs+5I&o;67$3o0*Zzs%Rc_C!$gPm*xzt@-ti%4 zx9t~XetQw~+m7^4^2$H!+0XtcT{y1%@yZVg1$g#0y1f~=?T>2M6v;t+voDy13u-aJ zuPzDZ=L)klIceq1v{kMUqqPg~nt7Ygt(fU%VmWEeAAnLmB%>K(TL`+vedElW0CQLMz-f{{^&l!;d6gy>G*)*q%Q%j-Xfy$ zI#h38`h{al{yJs~1y*YO#T)H5PqIYAjYT0VHHB0oku(fF3yI_$|MjYtv%-3<@?WoM zdHDs&D<}G|@sg$pI>+F_s$LiJcUy-LqK=Lh1C6RnVP#PNgCYL;zrvafJhxb#A zJk{gzILb;r7ku(w0^1~otyH_8bb*z6#5@foGCT6qpLnsBg^MMq>ExmWwfppopr$(y zt7zy}Q((|2<^PF!-Y4YUOwCPHU2CPLo3sI8egBSm9!N8j%u_Lv+gUu(#vrwEvuPt1 zuR1k$sp>w?%&>SS_6(krS-MB%@(iPqgs%Ba2D z0lgnrA{rA^>wabQt+(M7s>QwcAYWVWJA9@_@x7-YnpuOr|FNdizm1n+E2~$?T{c_V zK1{m@qUf@c+TWuOIlRnTwt9Qb_`K5i6G{IRW5XB67(;=TjF6|!zJG+OJeB&wEBaP= zB^9!XjyjV8mKxt7ceXMswU{@cFij*k#oK*odj>#%djal{-GSSWe(wofQbPkgrGn?= zJ>YqM*6#4U-v^%fkUp@iZTMmzZVcsfa#O5`vm<3N)nPCE9z$Q{uugtvp1~&f06O*9 z6<`iy_}Bi*H>(yQ?A1v7TZQh#Sw7=QCPXZDQNF(0N8GI{oE5^Cd+|LYnH7Q+BW<30 zws{{rg)B01VDg^KBL~Y)*4f9(F6-70sLPyiTplvw#@PG*LUm(xzA0jzMP$vx5vX2u zpT5DgZIq0KYTg<4Q)T1`bV^JU;f|WJynVdy0u6nMo#(go zUTkmuc#1Z-h=zZP#B#Eqb=4kOdx6^G1NB`2vIK}O(!&NITKhXZL~z2|VI>}+Wq>;d zsCp2Wh8-X%b+=WQE;eWP6D{vPH?Oet+`O7nuD04SbCdBi@cFp!Y{h){^_BAIMenHy zqDJKsIvG!-qYZ$=&Zo(UeK=lM8{$7{Vs1P%_n=TiC5xeUuML%F_|Y-Z4RKv9!K#~A zRmqr%Pd&%zzaB|nNBU`VDTBtDi&=3dMCHC)uK25w%4e>>-+sD$m-{7}8Noo9`(Yb@ zn`=2XpU#i|^TDBTiw67A5}L-{)}4!cqoK_!%+Sp!&J8_21M0-3*E1lAHCS}K} z7-)(p%<02!av0d;0W(D_XZJ4!ElzdI&(JqgZYpI$V?4r0RaMY&cIIS#j<^ROlE;cj zkGM8EB_*@EV5P*R1+kTi`%m0gWTnpKxnm$DA2#qpjCdi}+CE~Y);Xv2936GWNslp1 zEc5vNjn~%!*6qKhV4eLbu`37`wLSi_!?`@*;u&gz|J=h-ki~h#69LfE&K0ZK#>mdt z%?FOo7`H4p#sJpXTWjns^S1u!PnpcTEt4mQLhC3)`2YuRlw)%j}T@A?9D=S)DZ;lK`gaEbzEI z5Ie|yNOhpGW|JDW?pa$??uPBPvnw=)Qz8W-vK`OWV8q35kDw<#Md8d-vkyeoRFk?I z&&TBNX@#U4-#e$XW>=}&G|H8_N`mLzu&;@l;a+}(z-+5{FH(t*eFQ%{z>M1O#{Pzt zlQ2ZlOs9KXn(oQZhw%^r$_QC4BVc&G5o^lbaY^1dzffm@8u3m43AWPD(+EYB`yJ1sy>Kc zXkJrLUqi$_Wn3iDz5M z>u4;H{R&MX!VvA`bW2_3r!yOBQ<-qOmMPo?o`5GZZKvD#eYz;i6b57rMtmR_HOBVo z3|)2oHCWNs6c7=v^3&_*`sYXb!~gb=c7uPFhM+I}h_r>VD-A5%SkIzPYvC1*zCc_= zZufp_=qtZ&A(1{fg|~#c49$l<8AyjRbHm~L@Bw;M=$!&J!H<@$PPikn>&{viZe$V5 ztfjf0Hq*9nR_ZUtrwL-&V0V*0q-SUK-FP#r@0M&4?Aie17u$99-ik@dkXpH@WoO4^Lp-)Hx~7$!WY)tYk~tjn9rzMrM$187UH8%{RQ(<_%m6vPdqyTRMph+DE zZvwAhhWHyRv={WG%aL!{`Dbg7KG<8&d*HmoPxc~2!#p%!QyGbFvD2M_I#^MC(}5hV zh#k)wd5LMy8%#BsuK4>p2jM<#di2^Q-lu07Yt?k@*I2uUyG!|C^6PYfi>?u3BLBTS z^u6)eoWIl=Fpm8YiRAeUjL=w2n6PPt{+z@1Iu_16apQ-rrS!zD<|u^WBki%{YwXu+ z?9v*0Mq$ssXp^Al=NYA%^~GfWKm*LNi{K~#S(OLCsL(wO5VCo)4)1-AXc?K+9>u6! zSXPYQz}_nPB;;PGF2EIntiAHC(JGk0ze}q%f6}QCI?8}u!*b+vGVk5d#hMT+x^|Gm zUfN=QQcLvHnOe+`xMgRmjVB&>TEi2yfwg9R#!Rg;(`)T93KB|&_2iVXnFXtTgLnU+RV0!Vfb?b+4hv>A7)%x(6n?I}#&D#}fAPmMu zi4_J5m>2nujYDs!Fs(a|XGG?ik41cW6p=kNYrn`elfhcq*tV@Ul=pOE*J-m3MEPU2 zCJ(44glS~i8bY$6T5~)7I4aZEuj(L;G4aT zgV)19%7SI3@F&Cut)W8kyKiEJp1783K6(8SWDg(eDGk=|x-n+7tt4U6S?J!+k0#zL zj#{nb`t|n3Oot%uj!f&Ap7?u65a-2Lktx(>fVFNHH;*kz>^jU!!iHd2sg1N8O{^^r z+dHr^QF}+e_XOgEk1Fl3e_?>i5|g=TDT<*xjGDN`&q5+HR-DSa3XWsto@_YI;U6OZa}t@gF!Lq z{QF@cWfw#WHSP~7(OIGC9j_WM8H4zKn|S)vMW5=@X?2aG`aOp#AQ%DTl7=Y&BsO1}HJF159vDI2Hk~6&+V0tV!N){)r!BBjnJnzTUB~maHY)IiGdLM2WJr;*) zy1HD)hr^wDnBqe{Ys1#cP-S<#g^GJxl*v>We~|b8$|ILTqxSs9FZ~qH+0ro9P|y5m zrmJE@PeXb<6R4|asI?L%S!fH$cSdTrl^!x4f+^v9)u0=;EEnI1+Jn40#(23DYcyaM z%P~qQ@Dm17vvI%3CJa!*A$^KyrhBp`Wb1%+f>8Qx;7q+IWM_!wBz8G6mR>>eqWXC>W&S)kJiC(tP>rMPGruw+^0c;U*n?X@Ad zXi#2gWfxDz%<`K1DNZnKE+ZUQyGJ*V=MHKtr0Pgw?VvzqdkVTIe*=)+JN)o_yG#FR z3Ix)BsoWaZTFWj&w;JzAPXM>vW5rgf5pH>#t;%ab{blQvJwbkU{rS? z6Up9P$x?|?iUXi#o5u!&^D>DwBl^hR63n8V1DTfymZ3I$clu?>Nx8@RQttBq=r2S2 zLh)sUKw+qmWv9fDW&h#JKyuj}XfA;#Mi@FKM9@ec3+4KGTWE1xYzuM(aRr8RgIT14 zE7Hju=PYmTf|{4+li<80zI*B#Nb^|W) zjsQ4!H0ojdRlD;N?~Va|Wide{`5NK6-tNe5_9PbhQVH0Tf~YuJ`QG)XMAMhDM6-9t zGN=#hdpHupiOo({VC<@InFH)|N^d%*F8xE!6uvhThtoB~vl374U^?2Np1;b;e)k=Z zj~xC6Ufr>>ZBdlGb;CBd=GWOiVp85cA;sSQ&y@YmgpbYUd%$1%mF~{y+_JJ zdbDDpv(rZdR0qhDXj1nHf6Do2l`M{|e@|Z3_WRND_k8up;iKI-44ISz?E6i<3Y9K} zjr4QT#FxdYsl+#I$@5q{3#o$TVafWAu+8`442S7)Hol&B^vT3dbJuc=t}gF&j5kq^ zn)WLg?^H@k?)>%T2)gE0GrCr9{q>W*cZuF0BblzLS6;__U;IU$rZlF1HOiq?x8AgS z1!IW9;T-yaYjY{rxmSxa`+;F4<4WDV4`Biv2xKh6%%W(blbDCQcRT)+H&)28{`zjV z@reD7dnzD#C#ph2GgN_jJVCfF3A#a5CR|IeLRb0(q;kd2#2WIkd`%e_{0eZDGrp&| zq9)$0h880B+-`H{PJI`lKQiz|>(&EcdT4jAPos1tddLltX~VA3GZFG-u#W85Axp^o zHn8meoM0`IHEo=VM!Qok7Bbqj=}LaVXAa49MTl34Tv=;ZmEq(awcFh9u@H$8esYHT zv^P&a^`sRo9p~-8%N}kyo!7scWl(N4ZjFj>k{(~cCC}XEbZ&P9)m_9M)^_qC4#sqNYfC0^uc%*ew@+Jij+@bAQ1~ zu=fJ$Z_lFKZ1m?Nvo2PKVxC9|mzIG|E-%nzM0@$}2=@t&@1yH};5LpU5|0-dbr36G zVHteun2I*MPx=H!=yy4R@D*;DQzP$?`g-GMS z`{Zo8pP1WC=htSV858UV>Tw^^Ck~L?wJo_dW1rTk((2!OiJYR3on;e9l5^duH{vJs zoND&3+Myc83+11;>AXh z;Sn>)*uMvBzGDtw>>l0Q=;>#GJ*RdJ!|?6?u&JzcCqW+Bz@=Dh(bR5#{|3G7jF^G&0W0w+TV;1t!xxV@3}TlVQOf#K(V<} z8#odBaeN%^whK_0>8!)d3j*A93Jq5BWA%}vRASG!QsG3W>f=5Y9(WB?*tv3vad-`& zUi4K^n^>NT+bPAzOLO;x_*fd~tz5ZYr~cgl#*Z?7IXbmUI4CWFgO2q(;vULvu#i4QdMH#Va0#C@rMWpOG)Hb>!PR&Fl2Fp??DB{gj8 zxmUcw{O1=`7~< zwANYlQ;O`+fS;drFcMFuwE*GP~CWkGm*%~^S+9B*d5f*z$>KA!ZoetP`<>LdsJ z?qxq#-SE#7vD1}_LapR+e#-Gya)kdh(n_An6NgS(v=^+gYBmERVcclPO16>2wHJs$ zyXvQLMaQOdoxk zIak#=wKE98y}c%qhhy{>KqO_hwQNXZ!aLpE>aLCINNd>$Z#&!==L;)&x?vH|m>rLd z_Qh@#&ou@PYd)yPNY`ohFEVo$e^u*=kEzb~(BLPZ2M!MoMZdGP&u9;iW2eCu;m@AIp$F&=wQ1qn?NLai_yPt#YK zN=I<&QhgkOAw;ge6?CBtRcTqoOhj^V9C+2NL+K2A^=_hLL7Cif>fNQaC$-_mx7^1+ z+LfWEvb@gF*Hmk7!9%2!$u|~H(G5V#ngV%wPf>be`qD8OZxn#(oYFnSllZbEYok9J z0=ytkgOR9eni4;N?N5IA?-H?8`hH5QOzPJ>gdZ;U?h!DiH=IAwJ%+x1;dt4kGhH_g z^>3&WFX4s?N6;J#hj*Q-vme)qN&7XQN=}720K6d!OhDd;WMPPKx2ag? zy?~<3XMq17@QY*rTYhoahyQ=@i>W?O=)*7GW%%JB@C%();|YEt5&3`2FEUsg`tl3T z*{7)_s2Qj=+BqIDEC{*ot+AU+lLBwBi>V zvixF>4|rdGaTQ61UmW!B@{1wUSc8WRR=Tg(@-N$_FH{%C0 z&;1!c^M5hpbz;uUc*Q~1jNg!(@m6w_p5bA`BmaX5FJRN!0|p4%khCjfIcfs=lH?)96tzOgffM|Ad0Jo^&MG@9q~WW z1V3vfrLaP`;&yQuguO|$@?GoJUy~L^C7Y>dS*?8Ey5%nBl8oZGh2dD>a@o9$w*cdk;aQ6a!;3C-;^- zV~>)@^(iUHMnua$jsiop5>?hk09;RHS5R5d$4x;W|Js}H=6`sD$(R-RQ|rQywtZe3 zYH8q4omJD7_@j;=o7B>!vaq4Q%)cA8ft0Rv-^`!sL&k@G8Ydhf3G$(oNMnb-F@s@$}9Q93E~UZhzF_o?)4E*h$e}{~DgCy_zV5 z_%OBiltzs!JsEIMn%=}2nmW$w$@Q|Gu9Yh0Az={sS3?S(+b^3Naa?u&S>eI@>nENYmAXfYRokn22AjYXs~QVfmhntr_g~pPO9l=0D5aP5@ww<% zUZ;Qmjq=&a#ILVE4DL~Ey|(bIkgr4>jS_K@d(sTTbe{xvv>M}-^FHrHDZdqnRh`D?gd}Lm1|e zG9%~Dx(>dWp3*yx5pXTgf zd1nvtKnf3REW{J&aVfJg*k+z&D^63_H_OOQ+_*ls{?Ui{NmvoWjrD%m8Med|zRfOm z!J}Qo7hkR|-O4%OruAq1afkmA2d2+(J2GxtC-^Q-ZIN{Cl1Tb89Jx;Nk4wDfehZiY zh@)9Og9K2xv1S;8g%8sEUWkbvNfYiZJ$W%!jn3M|v=ed%?O>4+(oxP%w`vu1YwnU7 z)J;K#>9&$4FLpPhuv)I62r@3=%Mx!E?9^W{4Sypb@B*{#UgCS%6Wc*7<$JH;-u_ahmb9H&7QEglLcve7d}t%l;+{SK=c zqq(15`((psT4~tD-Rrv+A0X62#eGl@$40!C%*|(r5 z7}Omim8sST=3eKRonN%ALhW?+L0Y z7{&2AXv4Pv|E6y9v$RV;ov9Xn%m_d7#xDA@(Er-*;3ty|J}swS{3sfEbrK>6G+V{? z-FmXS%|}kHrzWs_2+BJLZePW{8oz;FI1-|USOqQ^%_^`J5At1RQu@$vq?oUf^wJp! zPe8MTH~s5O-L6vnGv5_Zl|X3 zu`|^W)adL_T#nflxf%Qoj<+mQrS{`~CUM@Clg5t^xd%?rtTs4t4y2T2KXH_rXjT(k zBN{n=p@HA=vB~*jHR#;3QGnYoXC@KmePd_p0aEqPN-1p@R((9c21s=D* zlz}9PPLXtaGbzYZ^pG6tVQ1=!+|$(HNiMYW+Fdq|ovBN6U#H}rF3dem%01QPo+7y? z-8tg7QO%S7b*8F~m_h%|sgb+16;v^=pt!34D%cpjPLyf7UNKLqd}TT!yzJWS8R{AZyrD}z|o@-dH!ikhFO=n3vroK>_b-AZ=CJa zj2>CBPW&RAE*#0cRzPvOkXPZw;u++ZE2NM}=gsJY0Cr zjwEDl5TXcB=E+@fghoCk0+`Odsg}L=2)Uq%=mhe8=1s-b!QSrSq|lk_9Vv~E$d8(Y zUW3}Y^whjQ=Kvs#AYd?#b90DhGkl&L^go)X=2ylI5vKegR-WMo>i5`*zySxUoh1KX=S zGw!)*|5lbj`b~7MUs3fbRiC#|V~u?9FRDK}SACuRuJ_V`;N2&51(AiWwX)>x;{I2b z)Vg%)S~`XNZUQoWi9qZ$Kfu5e72xmud>r{R6YuvtSb-Az-&b}1VkCT zM9?KZIoU9Uf(sbg5}SbUvUaDMD1Z~M|I-}etqwD~ozhbOlLHSZp@ zhg`8v7d2020*aFo#=@DWMg037(`T@EhwWDR0`E4bjsp*S&M8Uc{(2X2&KnUKa~{2T zVpJ&9NV30@XC{nL%o&9^@f*(=T2}k^5P7-{?*qhc6gLV+@s$+!{}91J$BRMwpss-E zmZj!`44;}4n|BQA7C9=ZA36TK&k*OxF?nJyiF_3~7E_l`j(WFgxaymw20mX)bQiTvZSn8#8< zhqt1|d#LwQ2}oD2D1i}KrkC&qK+h00JNGZ*Em%tfiR*Hz!JVY%a&2VSySm@mUa0Ch zZ>?In?0Ov2K%ypsnJQ;dsk1-EMY7txfUV#}XU-UQ;06SaRtrdkY^~nda?O#FFOCvQ z{7NeqD#Og*;(K3jbD<175C4OBJuD7S|8vrXCz*b!2fE=qsWWoM3&+GU+mBcBj5Ala zU5+Reh>+&G31>y407x&D2)SIsp?mozZI#y`T!UX>2G<#c`{2b&-VTo=Oq5Si8`v9h z?q`Kokqdlh?&LlA03=pup#hPbSloS~LOev`mcIdZPd5vAqD5i^N6TIoH=njtrL+ov z1`w>kUJG>vV$$~NSfQ1gid^*-9C|7<5I=DrFdDmYPp*h!cJIVC&0n%H>-?5=&Rak* zi$JF8Ol5_ve<@wn5$0mA(p4VP)yewki)o#yNgzFsj{nOlKl|h>sti%(KlIUQ7VXrf zzt=1DjnAt(&Pr|vqd32IrmAU79!iGzIbU*n(tG`4pf%^6ypk63m;)81BvaDF2^>*45RG_TF$GVH!bI_VG zsrrsJf3BL|+ty?kAWzlDUN{3L!Ov9c(l#fH?K4@ncas}#x%5z_q}mL|jM&SO!hr9F zi=6`qNpIvztMThh9)G0v-r=KIUjD}&_6}fTW;tDFN*h37-Abj9{~r^f71+BNyyiO&jUW0w7r_e(F?$%`bn|Zw= z$Ye}bfrwJkmXnED@HHKsg(7ccVjtniwVL<#!fP4NybX3r!f-$gNVmQ;>Xs{)*|ysBhkKPKw|TmgSy(c4m4@n zSnno?P>+#90vTkP*>L+Jv13}7>^RPF&3>ZsjYt10StQuUrkf-5)fY+hG>2NH2 z01LeL4T2|krmhAq$s~vtLQ`kzTK@8mxX`OxP`{OC1dr_$-hJs`s<;e$Ed6!PafuZg z3a(wa30@owt(E#IFLDD<&Ez4mLJ;67e!m!xS%eZRg!53a2t7ZZuspSwbEhf$x*_Eu|F`51Nb zv`4w+Bh%a-!kxAoSF+uxaSWB4s{wwtO*=!g8_lG}KXooIIo*(w0o1QDaS9Towms*W z%`->-jRMVVEwX!xQ6u)Ur+EK;CfQQaf3T+@EW&UO*LZhJT+41t!fZ>zY)j^SgKlw} zvCqE5AU0V0;a>|Rkyxqs{e4-tL1>^*OKb!wb#@P7Z3awqVq=C+bS^~bD*p%#o8C(& zI(1`)>vFyF$8|+*>U?11P@vHwmUsF4_pFpL=D`x`wi2VsBW(}5Ew#))LJ1AP5>z*C z$XQNoT%q07<`!U-;-@h2dY-+??y?tllef(+V*j8ocC+O4Hg`boyEb@juC}}O6Rg&D zv)KYuI;BmqYS7NS+f{93YIE~#vpuKX3&-u-{f_-?+dKKHZQ;YpznTD<N|3x#t-)PiTDDM zc^O~)Sinr!BM;Ce+QtQntP6?M`nEX7X1nOL8khb#6t_le?S~ z7@h~#_OgFC@|j@&Al9jAV)hTigBL4#3mnBULN&DI?;f;$%kCbo;b5G<03c#C!F79g z4}W99@I{h89l!hT;Xp1fVE3S9L%WB^071KlyQs@=s+ZA=sZFtjjlRtMmxjIf*FpB( zhF(kE#39s=zYo<-W%l!RR;}xu115a6tPwk|ct@|3$f@pkrXoC<50m+@2dDcR3~XDJAym8)+)#vK1L z`Fq!RozoU1_)I+FFRB74SizPH^D12qiZ({9$SPJd+jPcCMd^<(8gMqez$E(W-Muz* zL?D5?`F?vPR;}5C_&X8qaG}+~M(P=CtS&_3Nf`M()38EQvD8W~Lc(yCDx+cn{niKt z#wN590iHn}&!RV;MX$J2q`*Z~W=V}?!Xx~pa<6a&-N#Sjbh__v;qnY*KEND~>#w1f zMD4zMLq82QMCA`o6;NY5Yv4pFV`*rzKWMJ=afKmSo~j&Dc*7krgOsWY2Zj ztVqvJcrA=fc$EgTsx6rJn)Ih_qHilCrZDHx?rB2zoAOskrM*#3VFX zX0rF25nl}sGhWzZ#vipm6QaNfRm5n&>Ck}eqtjk6H$}Uj&+Mgq!)X4!IeyOTjHuZ& z!5D)%{xitX@3-do31ILm=lB)K6MO3s28@5FQ=3?obFJH{d+2I`FEN&P_(ER5(tLU` zOPb%^!T-DNUb>a8rPWSeS~Ff@`tSIyQS6w?g-$p!_pM&XM1R+8uFMDbJ6DoWwi&YZ zeE|q5bnr1NGhUP$b%M-%KS|XaS`p?7`fz>uhi17xUUpXEIK+>R(D8j3zX^%oTlx#b zTm3a-kJ1D7Ed7w-%-V{p?eqS-($^t7^=tb-DCeY2X-+RJHKh%euJqfUz`ayNBfLO5jgx(}n6)*FmMe#UC0bMzw3v!~ zw6s3k2QBZsiY0xalnYkl^=wI4)Ti=-C>=iztF*6m*tCb-V$k&UT&J?rwV&=?(`w3m%7oh70yvQFU*huxYmU*@B83KD4 zY#VLLe4|}SwU~EQaz{W1!Rqbrm;LRvH_iwMDy9hd51Ud8{ZhOq%(kts!0V z0Q(3G*y?)T5C97&8OSMGN>#h>ai*Ed`WLNnj`N&%A*>a`ek!wf?ELZSEOt7Lh$-^$ z$}wr|m7;%|%Z;hbdzUWu7hIfCCHP$Iq(xzO)6>A3^|^TLV7zt2@y(=Z`-(|3JlDj( zpoWX64!rcv8vF^qV%n_vVYZVI$9TYa&5UYpw9i3DA2zm8@9|f}+OH78Ad+#$v||_~ z7rYtXXeACnDDMcBBAaxR%`nD&$mbZbL8Uy&m-5nl?BmDa&5~Bc-yH{(W?bnKZ8%5C;4=x4^Sol2 zES!+tyg)PFcd_vP=H*HTzCE7N`u3-}$g~5z-x)?^TnHeJ(FmtQR_SiJ)RdQXikd(F zI~c+;67{Mlz5VG8Y$nMdz-9<#zn|#ge*gUq%RYoXdF$pvTw6-I?Goc2dJ&UP9|!Xxy$2hVnJRo4ffS|2>n#$w%E>uIbDAOmm5jl3Y8d z&`#JX{B>eyQS6kPel}KTCAj|b&fBOzv2%dhBPFqOVBm6&>j3YB&$g27djaA4@Se?M zxFO<2xi^o|GJT&ot?oB&H#{h1SRgu;s72Q+V-A z%)Luh(ba6J3s|r-rD}Q6f$iJ`GZt|LQyv|q!-)>mE%yTcc)iXTXkfKP?t&fC!3=xI zFozaIHsA8%j?}BJ76<$#x}DXhEr7+xTkywm_!t(zk2Vo%^Pumep#1sb6v_DWso-bY zrSB)eth2`+uBDgx?w^qQGBx{R%jCgci&|{4>vfC#d~J*0qR7Eo{A!!uqWi;xbuQ>P z^{+aowr5o5-U8nTYwD+&rb2|{bXOt+Fc*5_@&n5LTe!?N_s6ekZfK@C_a=4)Gh;YI zID9X^FgN)cAEzkCTl|>WQQ8gm(UBZ}(7EIXol8DKx~Q84OEC1KNxqPAwGp2+e7l_Z z7QQRGdl|ss`KqkY-*u?yB1r${Gy#CS!ai{4$|c9zXGb?%t{Bb}rToyW{Lrj?{8!Bm z&NTZ&-K;7r&AtJrl4gfxoBfYZ)Fc>Qj(8uCHgdh@mBX!j=S%7ISpkZ=t^2Z>3lGRF zU)&F12rQJ7d3HW~M$6j|t3^E_-x`Mpjl=`Iy9G=#kALF~MHDJ^;DDccvT-sf-*?DK zE8eF>0&hqAZeS7S;_YZ_4;pgr-fkzRW3=V*>1 zir)o}dkeGXlp)3LEJ6O)Lq1xyaUfsorbqT#wKTvZpA{o-kIl9-vLlcSN$y&6EOH`Z zcs)3i-K4~Ss!DPP?FK5z88jAPoZHE66}cNgS?=N&Q#d{mn9C%mbheRt{2s_AYE@+?)k>Sy{I0{$2#`(&!stx0Aks9aBK#Itp zS)_iVCR?s}AJbNCq37J;GoC!moyyeCAy#Y)nR-rA^<>&m-_Z!v3^|Qry;n}tc#@^_ zICh=%Qr!!BnVz1|{8N#ozn)6>KL1aXuYs56fSiH1ql535^QI^s$zGV8=Phe>l|-+; z3(L-aU%(rR$Yy?=WBxPqY;sqW^W~|;9aQJz+!ex>y=AT{Apnm<7JbbaeEvd)E_!Im?u!ZyJ;8(i6fwO`p5y-TI%})&AY~;MSE$58vdD537;B1{eZ%v= z(k?2K#Xg>_InGy z+P+TO7Tap3ZSL{;y0&v__u4*P+MXdk2+6gwDmuU2s29`^F)=ZN z>?QKz`{`u8h~06DQ2O33&BV2CaEm)eX4I$YQMA&31?L!D{%} zmhHO8VpWHcuvrPD3L~eAU#Kd?Sg)#>O%|_;KS~wfL0*(15wD6Dgw62&*8sl~!Bd@5 zHRAmQ+$qYg&A16G#jCxz#BCwJviDP_(5vH@!d-Y@(5sFOXrh@qmPj4$LbA#LGd)eQ8itNXIn#sQ1d5JG%$6g^f0zleYe7T_1 z-I^`-h!ndxx7Y)^m=Txj&vQ%lA(w!0a;cuiN2n!lr?Z@EDsu7ju9TaiEK~?`s&9SC znk5$BTzgn8Bz`;oJE zIf;`rm`xy8-ur4W6*1jK?i^y8PZmw&$KW-giM&;a{P?SL;ZEJ7+eRgi`xLpO;fOnXVFx9g%-Joqy{IqCH<;cVp1kg=pq z46BJhkT^9q2WyJ8kVgr=WJ>V6Dyy~Z)5Pm@k7U6R7aF;!#oEOdWo2ufQTKr=a`RZK zXc%70nN<6i!E%AXULG9IZ^ZsxuuAs6{u`h7n0B5Z5CACMhzcU(Nt#R;CaobCeE+sa@ zIfFuL^T5V3;uu`S!?MO`Nf?xshDS(n!PqM*_etS2pLF*0re#&^%#$~pPi?Oov0{~Z zSkKHQ(POe1jhNh*g0F?n!v$Zlxkcqhd_L8My3QF~*faC7DswoKnd^^b+5QZGL$R~d z(aUpdevCTW0)!F~=%<|Rh5aXD3ipUPp(ll9w5Em;R5GlC;kAZG5M|GZok+O_`KlOZ zCpksBUFw&6xW1g;5wg!IOf*MNRE4|}I}a%FdtHJ6xgB!u9RkW8eQ(VLlAtXBIaK#Z zqn|z^FTjSImK7QCzw(emQ;G$%cJc5lWHa=XTD z0Um^*wKAyz5>P{vBm)1I9&pMHF&LeE%)6IK-75*<`kvG8aX914+4ru;_NP<7Rm-aL zKF@G^<|RTlY|?$7d}@)Gl7H2yMq(#PrSPIlKN*qbrfGE_0N)eikI5tr?z`# zntrB3%#U-42UklVVUUg||URY4`!o~i4Y*PZ00e$Ov^tXKAXWbyj?P14+Bq%K+d z1j<4$cYGxH1M_Yjr92iYd=o){h%7qFFqZ|6Ddj=|dj|7weJ3?oTgyJ-EdIC65o5|{ zoLRM?%;ey5m9dh`!~IaSL>ZEcopk(&J2a=-CY}`3WtO2lk10(xQ{;12Koz@I7nK0H z*FU;H6RS(Y4Eg*+;oXvb=^fiQq(7z{>6!r$`vZbuFPZwwP~}wO2F~=%xGJKdp-{3weU6N_)F6GaS`i9S%D(fkYLEJ z-T`AgBow=4%~T^U>pM;agmiC?j)vkp<=)Mi_PB99cUmd zD|rc+s?!=24y0S`7aEC^nEPgXO(%U0xaaVq=WEEm@QsQOlhyc8hOFv0j72FpM;0`1 zJ`zaT4_O2@xsHumjFl4x%V}z<*LtE}Ri7Bn4-K$ee!Bmpqf~Jy!2gg4dQVn|9Is5NtW>0NZe29RZ<1rFycQ&Z_+lspP(D8RlNsLsR-BAEBi5yaN2 zfm2Sy4gY~rM3RtS9Gqp4LM1=FGZH)Gy*=UM)WfnuZJxe2&9wVO?2=mhYNp=ro1v;& z>*3A(aP>)Zt#!lZh!qUhvg#B%_toc%X(N6OomE)teShgm0yK6&`*4Xd6hFR1U`a}6 zLu-EoLkz8p^4FXaD(vDa)4T=*#4FY3IDfO0=iWgBfMwd8M|(gnDC1@pLZ%&-kY{K9 z`5KHLVOLXNWJ~r2=$`H#09}6EKL^N2+(VsqQlOm#y+>RXUd{7Q<#P64y)Ubr7ydhY7AL_y?spsKqN^o)7Oukj_FycQX_i9>2 z%kCAsDU1H6xFK398VpGv6#dKg^yqB|duAE*U!(B+v)<^xL4E!me_wxC#=fHY)sJ?% zf7@Z)3o#2CSQZho3w;(A6@^NSu#bPQiog6aCv>R5Xz9ITk zd%<(kDzT80)uRYCXq>O}bD7UPsv3J=IQBtt2z92YHg9)&b7l9uOT|?yzMYW_+k=8* zNn%EArN*VEJ*SDQ*`76lKb+p|Jo0^6Gg`Ra1(Wv(lT1DlmCh)u4JK{u2y|?p6H37(2N?oc2)65j-uNB_=w5VEK_iV&B@PJ>5d<@y&BgRRAaxZC8JT0N7zumM{>dDkygR{C- zF7*;pjhc=4Zb5ze8Qp}qPd6<0P}LQJ)yT0DpVdUqU{g?9gU`smV051~Cs8->T&OQL* zHEvkyxBGVVWegtfR?i#dxn4i7lIL;gI6jw8j$h6efUq5(-ejAb*L5I|_?%bda{{~> zPO(Db)zu|u{nfovn$4E;@@JT)F8Ig+1zX&cr69-i6o|fW$#ZnBY5~3_s`F?Q-BO#N&&Ytntry=0Ne z%*0>%)Nl%O277b2ARPABVZP{ac@-gS+`@+4=8NweD{rehb97*J6&dq3b6-3>po|c{ z+|$?DudJgsxndr`uM*U}*f~J)NuNdB@i%&Bt4}Z`t8TfmNbaZr?xpye#kia1cmj07 ze$Nav9EC#`mj<_Vay{5c1fu@@6a}I#usz?cp!^rGaal*+=1>`ix!b>i6!f~Ws2!Lh zQ&ND+^*Lq8z1@M-G3VL^yL1Rrg#vDLBVAG}JLbJ3ym@SyD_4b#y^lb>Ua7eXOiI2F zA2zLg$tIV%c{yOk?~E;TgnhdrCE7|hmC5Y|tI5h)e_?)S<*YX|Qekwr;+2K4O7{`P z1C$u51f(i`gH@JE+@EC<2k?jG_*AzChA|lK>x#5`uJp6dCgD&`_s#jx{YG4;Jo@W( z;_)taHE_@< zw%BA|Mc7%m{6bN9#;?!|(yI2lqLd%1-_Kym=jW;&(wkvf^Yc)3dE_-B0zlK*n zk{UL77oOvj2x@dO)WXY@Z>}1y_QYp^f({a}^ApXpzGTmY=W#T(A zL!`5$e6Ae3+*tTyUO7A&+>aNud~8qbK59nI09d+xj&w!bkOSrLJCewWF%hz zzFdg0_p{W*-n@7INCsgZ%TcX$<-%I~_|Q55G~0v*o@(dm+N4>Sdz}&fj6-&XbzC!~ zTaB$%Vtn*JIPoJ-_F93`xnMV-svK5AMucq%0kRG)IXQBZz?O*|Fa~Wv8)aqv_)xS5 z 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

#(kaBB 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 literal 0 HcmV?d00001 From 81e81a86040b4504f4b7ad535d6bcfda2dc90114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Mon, 15 Apr 2019 08:14:08 +0200 Subject: [PATCH 52/97] doc update --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index b80fda4c..7c26c275 100644 --- a/README.md +++ b/README.md @@ -1614,6 +1614,11 @@ A convenience script to execute several applications automatically [**run.sh**](DRAMSys/gem5/gem5_se/run.sh) is provided . Take a look and learn from it. +### [MiBench] + +Applications available for x86 in [DRAMSys/gem5/gem5_se/MiBench](DRAMSys/gem5/gem5_se/MiBench). + + ### Boot Linux with gem5 and DRAMSys The procedure is very similar to the traffic generator example above. @@ -1955,3 +1960,4 @@ Architectures Modeling and Simulation (SAMOS), 2016, Samos Island, Greece. [DRAMSylva.sh]: DRAMSys/library/resources/scripts/DRAMSylva/DRAMSylva.sh [DRAMSylva folder]: DRAMSys/library/resources/scripts/DRAMSylva [configs_json]: DRAMSys/library/resources/scripts/DRAMSylva/configs_json +[MiBench]: http://vhosts.eecs.umich.edu/mibench/ From 205736173ed605a5ad0fe91563532727e5381536 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Mon, 15 Apr 2019 08:27:47 +0200 Subject: [PATCH 53/97] doc updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7c26c275..05dffa84 100644 --- a/README.md +++ b/README.md @@ -1616,7 +1616,7 @@ from it. ### [MiBench] -Applications available for x86 in [DRAMSys/gem5/gem5_se/MiBench](DRAMSys/gem5/gem5_se/MiBench). +Applications (x86) and configuration files available in [DRAMSys/gem5/gem5_se/MiBench](DRAMSys/gem5/gem5_se/MiBench). ### Boot Linux with gem5 and DRAMSys From 7a5ee0e52e107642c43b143cb11027ebb45c6372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Mon, 29 Apr 2019 14:27:22 +0200 Subject: [PATCH 54/97] doc updated --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 05dffa84..b53f4be7 100644 --- a/README.md +++ b/README.md @@ -1868,9 +1868,9 @@ export LIBQWT_HEADERS=$HOME/qwt-6.1/src export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}$LIBQWT_HOME # Python lib -export LIBPYTHON_VERSION="3.4m" +export LIBPYTHON_VERSION="3.6m" export PYTHON_HOME=/usr/lib64 -export PYTHON_HEADERS=/usr/include/python3.4m +export PYTHON_HEADERS=/usr/include/python3.6m # Gem5 + DRAMsys export GEM5=$HOME/gem5_tnt/gem5 From 861478e2b6b926f949cce6670fe1d89230b77e4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Mon, 29 Apr 2019 17:55:56 +0200 Subject: [PATCH 55/97] improvement --- .../configs/simulator/rgrsimcfg-gem5-fs.xml | 19 ++++++++++++++++++ .../resources/simulations/rgrsim-gem5-fs.xml | 20 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 DRAMSys/library/resources/configs/simulator/rgrsimcfg-gem5-fs.xml create mode 100644 DRAMSys/library/resources/simulations/rgrsim-gem5-fs.xml diff --git a/DRAMSys/library/resources/configs/simulator/rgrsimcfg-gem5-fs.xml b/DRAMSys/library/resources/configs/simulator/rgrsimcfg-gem5-fs.xml new file mode 100644 index 00000000..47c6a016 --- /dev/null +++ b/DRAMSys/library/resources/configs/simulator/rgrsimcfg-gem5-fs.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/DRAMSys/library/resources/simulations/rgrsim-gem5-fs.xml b/DRAMSys/library/resources/simulations/rgrsim-gem5-fs.xml new file mode 100644 index 00000000..a6e1ad3c --- /dev/null +++ b/DRAMSys/library/resources/simulations/rgrsim-gem5-fs.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + From b37bdf3734e0ad225b7260bb32c99a81c90907b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Tue, 30 Apr 2019 08:58:21 +0200 Subject: [PATCH 56/97] doc updated --- README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/README.md b/README.md index b53f4be7..bf3abd17 100644 --- a/README.md +++ b/README.md @@ -1618,6 +1618,34 @@ from it. Applications (x86) and configuration files available in [DRAMSys/gem5/gem5_se/MiBench](DRAMSys/gem5/gem5_se/MiBench). +### [PARSEC] + +Full system simulation files for ARM available in [DRAMSys/gem5/gem5_fs/parsec_arm_minor_2c_8GB](DRAMSys/gem5/gem5_fs/parsec_arm_minor_2c_8GB). + +Choose the benchmark in [parsec_arm_minor_2c_8GB.rcS](DRAMSys/gem5/gem5_fs/parsec_arm_minor_2c_8GB/parsec_arm_minor_2c_8GB.rcS). + +Edit the paths in [config.ini](DRAMSys/gem5/gem5_fs/parsec_arm_minor_2c_8GB/config.ini). + +All files required to build DRAMSys_gem5 and execute the simulation (gem5 +library, benchmarks, disk image, etc.) can be obtained with [gem5.TnT]. + +Start a simulation. Example: + +```bash +dram.sys/build/gem5$ ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/rgrsim-gem5-fs.xml ../../DRAMSys/gem5/gem5_fs/parsec_arm_minor_2c_8GB/config.ini 1 +``` + +Optionally, open another terminal or tab and connect to gem5. + +```bash +$ telnet localhost 3456 +``` + +Note: the port may vary, gem5 prints it during initialization. Example: + +``` +system.terminal: Listening for connections on port 3456 +``` ### Boot Linux with gem5 and DRAMSys @@ -1961,3 +1989,4 @@ Architectures Modeling and Simulation (SAMOS), 2016, Samos Island, Greece. [DRAMSylva folder]: DRAMSys/library/resources/scripts/DRAMSylva [configs_json]: DRAMSys/library/resources/scripts/DRAMSylva/configs_json [MiBench]: http://vhosts.eecs.umich.edu/mibench/ +[PARSEC]: http://parsec.cs.princeton.edu/ From 9b7d14b35326d086919d7b5a0b83c627473570d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Fri, 10 May 2019 07:38:38 +0200 Subject: [PATCH 57/97] improvement --- DRAMSys/library/resources/configs/amconfigs/rgram-rbc.xml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 DRAMSys/library/resources/configs/amconfigs/rgram-rbc.xml diff --git a/DRAMSys/library/resources/configs/amconfigs/rgram-rbc.xml b/DRAMSys/library/resources/configs/amconfigs/rgram-rbc.xml new file mode 100644 index 00000000..689aad68 --- /dev/null +++ b/DRAMSys/library/resources/configs/amconfigs/rgram-rbc.xml @@ -0,0 +1,8 @@ + + + + + + + + From e955c8626993d75e46d32755131c365a9b876446 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Wed, 22 May 2019 10:02:30 +0200 Subject: [PATCH 58/97] improvement --- README.md | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bf3abd17..3db7f49b 100644 --- a/README.md +++ b/README.md @@ -1618,7 +1618,7 @@ from it. Applications (x86) and configuration files available in [DRAMSys/gem5/gem5_se/MiBench](DRAMSys/gem5/gem5_se/MiBench). -### [PARSEC] +### [PARSEC] FS Mode Full system simulation files for ARM available in [DRAMSys/gem5/gem5_fs/parsec_arm_minor_2c_8GB](DRAMSys/gem5/gem5_fs/parsec_arm_minor_2c_8GB). @@ -1647,6 +1647,116 @@ Note: the port may vary, gem5 prints it during initialization. Example: system.terminal: Listening for connections on port 3456 ``` +### [PARSEC] SE Mode + + +Binaries and gem5 SE configuration files for ARM available in [DRAMSys/gem5/gem5_se/parsec-arm](DRAMSys/gem5/gem5_se/parsec-arm). + +Use [gem5.TnT] to download parsec. Example: + +Go to your **gem5.TnT** folder. Then go to **arch/arm** folder. Execute the +script *build-parsec-serial.sh*. + +```bash +gem5.TnT/arch/arm$ ./build-parsec-serial.sh +``` + +Extract inputs files. Example: + +```bash +cd $HOME/gem5_tnt/benchmarks/parsec-3.0/pkgs/kernels/canneal/inputs +tar -xf input_simdev.tar +tar -xf input_test.tar +tar -xf input_simmedium.tar +tar -xf input_simsmall.tar +tar -xf input_native.tar +tar -xf input_simlarge.tar + +cd $HOME/gem5_tnt/benchmarks/parsec-3.0/pkgs/apps/fluidanimate/inputs +tar -xf input_simdev.tar +tar -xf input_test.tar +tar -xf input_native.tar +tar -xf input_simlarge.tar +tar -xf input_simmedium.tar +tar -xf input_simsmall.tar + +cd $HOME/gem5_tnt/benchmarks/parsec-3.0/pkgs/apps/blackscholes/inputs +tar -xf input_simdev.tar +tar -xf input_test.tar +tar -xf input_native.tar +tar -xf input_simlarge.tar +tar -xf input_simmedium.tar +tar -xf input_simsmall.tar +``` + +Open [DRAMSys/gem5/gem5_se/parsec-arm/config.ini](DRAMSys/gem5/gem5_se/parsec-arm/config.ini) + +Edit **cmd=**. + +Edit **executable=**. + +Examples (**Replace USER. Use the correct path in your computer.**): + +``` +-- canneal -- + +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/canneal/canneal 1 5 100 /home/USER/gem5_tnt/benchmarks/parsec-3.0/pkgs/kernels/canneal/inputs/10.nets 1 +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/canneal/canneal 1 100 300 /home/USER/gem5_tnt/benchmarks/parsec-3.0/pkgs/kernels/canneal/inputs/100.nets 2 +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/canneal/canneal 1 10000 2000 /home/USER/gem5_tnt/benchmarks/parsec-3.0/pkgs/kernels/canneal/inputs/100000.nets 32 +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/canneal/canneal 1 15000 2000 /home/USER/gem5_tnt/benchmarks/parsec-3.0/pkgs/kernels/canneal/inputs/200000.nets 64 +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/canneal/canneal 1 15000 2000 /home/USER/gem5_tnt/benchmarks/parsec-3.0/pkgs/kernels/canneal/inputs/400000.nets 128 + +executable=../../DRAMSys/gem5/gem5_se/parsec-arm/canneal/canneal + +-- streamcluster -- + +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/streamcluster/streamcluster 2 5 1 10 10 5 none output.txt 1 +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/streamcluster/streamcluster 3 10 3 16 16 10 none output.txt 1 +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/streamcluster/streamcluster 10 20 32 4096 4096 1000 none output.txt 1 +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/streamcluster/streamcluster 10 20 64 8192 8192 1000 none output.txt 1 +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/streamcluster/streamcluster 10 20 128 16384 16384 1000 none output.txt 1 +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/streamcluster/streamcluster 10 20 128 1000000 200000 5000 none output.txt 1 + +executable=../../DRAMSys/gem5/gem5_se/parsec-arm/streamcluster/streamcluster + +-- swaptions -- + +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/swaptions/swaptions -ns 1 -sm 5 -nt 1 +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/swaptions/swaptions -ns 3 -sm 50 -nt 1 +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/swaptions/swaptions -ns 16 -sm 5000 -nt 1 +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/swaptions/swaptions -ns 32 -sm 10000 -nt 1 +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/swaptions/swaptions -ns 64 -sm 20000 -nt 1 + +executable=../../DRAMSys/gem5/gem5_se/parsec-arm/swaptions/swaptions + +-- fluidanimate -- + +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/fluidanimate/fluidanimate 1 1 /home/USER/gem5_tnt/benchmarks/parsec-3.0/pkgs/apps/fluidanimate/inputs/in_5K.fluid out.fluid +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/fluidanimate/fluidanimate 1 3 /home/USER/gem5_tnt/benchmarks/parsec-3.0/pkgs/apps/fluidanimate/inputs/in_15K.fluid out.fluid +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/fluidanimate/fluidanimate 1 5 /home/USER/gem5_tnt/benchmarks/parsec-3.0/pkgs/apps/fluidanimate/inputs/in_35K.fluid out.fluid +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/fluidanimate/fluidanimate 1 5 /home/USER/gem5_tnt/benchmarks/parsec-3.0/pkgs/apps/fluidanimate/inputs/in_100K.fluid out.fluid +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/fluidanimate/fluidanimate 1 5 /home/USER/gem5_tnt/benchmarks/parsec-3.0/pkgs/apps/fluidanimate/inputs/in_300K.fluid out.fluid + +executable=../../DRAMSys/gem5/gem5_se/parsec-arm/fluidanimate/fluidanimate + +-- blackscholes -- + +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/blackscholes/blackscholes 1 /home/USER/gem5_tnt/benchmarks/parsec-3.0/pkgs/apps/blackscholes/inputs/in_4.txt prices.txt +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/blackscholes/blackscholes 1 /home/USER/gem5_tnt/benchmarks/parsec-3.0/pkgs/apps/blackscholes/inputs/in_16.txt prices.txt +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/blackscholes/blackscholes 1 /home/USER/gem5_tnt/benchmarks/parsec-3.0/pkgs/apps/blackscholes/inputs/in_4K.txt prices.txt +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/blackscholes/blackscholes 1 /home/USER/gem5_tnt/benchmarks/parsec-3.0/pkgs/apps/blackscholes/inputs/in_16K.txt prices.txt +cmd=../../DRAMSys/gem5/gem5_se/parsec-arm/blackscholes/blackscholes 1 /home/USER/gem5_tnt/benchmarks/parsec-3.0/pkgs/apps/blackscholes/inputs/in_64K.txt prices.txt + +executable=../../DRAMSys/gem5/gem5_se/parsec-arm/blackscholes/blackscholes + +``` + +Start a simulation. Example: + +```bash +dram.sys/build/gem5$ ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/rgrsim-gem5-se.xml ../../DRAMSys/gem5/gem5_se/parsec-arm/config.ini 1 +``` + ### Boot Linux with gem5 and DRAMSys The procedure is very similar to the traffic generator example above. From 503f9740370da0eb5e0ba7efc2d77cd053a0b111 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Wed, 22 May 2019 10:06:31 +0200 Subject: [PATCH 59/97] improvement --- DRAMSys/gem5/gem5_se/run.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/DRAMSys/gem5/gem5_se/run.sh b/DRAMSys/gem5/gem5_se/run.sh index 363340e0..0e642cf2 100755 --- a/DRAMSys/gem5/gem5_se/run.sh +++ b/DRAMSys/gem5/gem5_se/run.sh @@ -97,7 +97,9 @@ for s in $simfiles; do cp $sf $simulation logfile=${sfn}_${bin}.log # LD_PRELOAD=/usr/lib/libtcmalloc.so ./${elf} ${simulation} ../../DRAMSys/gem5/gem5_se/${bin}/config.ini 1 > ${logfile} 2>&1 & - ./${elf} ${simulation} ../../DRAMSys/gem5/gem5_se/${bin}/config.ini 1 > ${logfile} 2>&1 & + date >> ${logfile} + time ./${elf} ${simulation} ../../DRAMSys/gem5/gem5_se/${bin}/config.ini 1 >> ${logfile} 2>&1 + date >> ${logfile} done done From 15890f96d3be334ce9619abd0460f30dcb1226b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Tue, 28 May 2019 09:36:59 +0200 Subject: [PATCH 60/97] improvement --- README.md | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3db7f49b..efa273b3 100644 --- a/README.md +++ b/README.md @@ -1614,10 +1614,6 @@ A convenience script to execute several applications automatically [**run.sh**](DRAMSys/gem5/gem5_se/run.sh) is provided . Take a look and learn from it. -### [MiBench] - -Applications (x86) and configuration files available in [DRAMSys/gem5/gem5_se/MiBench](DRAMSys/gem5/gem5_se/MiBench). - ### [PARSEC] FS Mode Full system simulation files for ARM available in [DRAMSys/gem5/gem5_fs/parsec_arm_minor_2c_8GB](DRAMSys/gem5/gem5_fs/parsec_arm_minor_2c_8GB). @@ -2040,6 +2036,45 @@ variable. export DRAMSYS_DISABLE_COVERAGE_CHECK=1 ``` +### DRAMSys + GEM5 x86 + +Change your ~/.bashrc. After that close all terminals and open a new terminal. + +```bash +# Gem5 SystemC TLM-2.0 coupling (see also: $HOME/gem5_tnt/gem5/util/tlm/README) +export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${GEM5}/build/X86 +#export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${HOME}/gem5_tnt/gem5/build/ARM +``` + +Change the architecture in [DRAMSys/gem5/gem5.pro](DRAMSys/gem5/gem5.pro). + +``` +gem5_arch = 'X86' +``` + +Make sure you have built **gem5/build/X86/libgem5_opt.so**. If you build with +[gem5.TnT] you can check if the library exists as follows. + +```bash +$ ls $HOME/gem5_tnt/gem5/build/X86/libgem5_opt.so +``` + +Build DRAMSys as usual. + +After building, go the the folder where *DRAMSys_gem5* is located. + +Test with a hello world application for X86. + +```bash +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/hello-x86/config.ini 1 +``` + +A **Hello world!** message should be printed to the standard output. + +### [MiBench] + +Applications for x86 and configuration files available in [DRAMSys/gem5/gem5_se/MiBench](DRAMSys/gem5/gem5_se/MiBench). + ## References From 6ee31fb9d6690b72efb7935b7023370cd3a9bab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Tue, 28 May 2019 12:05:33 +0200 Subject: [PATCH 61/97] improvement --- README.md | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index efa273b3..956d8b07 100644 --- a/README.md +++ b/README.md @@ -2010,7 +2010,7 @@ export PYTHON_HEADERS=/usr/include/python3.6m export GEM5=$HOME/gem5_tnt/gem5 # Gem5 SystemC TLM-2.0 coupling (see also: $HOME/gem5_tnt/gem5/util/tlm/README) -export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${HOME}/gem5_tnt/gem5/build/ARM +export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${GEM5}/build/ARM export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${SYSTEMC_HOME}/lib-$SYSTEMC_TARGET_ARCH export PKG_CONFIG_PATH=${PKG_CONFIG_PATH}:${SYSTEMC_HOME}/lib-$SYSTEMC_TARGET_ARCH/pkgconfig @@ -2038,27 +2038,43 @@ export DRAMSYS_DISABLE_COVERAGE_CHECK=1 ### DRAMSys + GEM5 x86 -Change your ~/.bashrc. After that close all terminals and open a new terminal. +Make sure you have built **gem5/build/X86/libgem5_opt.so**. If you build with +[gem5.TnT] you can check if the library exists as follows. ```bash -# Gem5 SystemC TLM-2.0 coupling (see also: $HOME/gem5_tnt/gem5/util/tlm/README) -export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${GEM5}/build/X86 -#export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${HOME}/gem5_tnt/gem5/build/ARM +$ ls $HOME/gem5_tnt/gem5/build/X86/libgem5_opt.so ``` +Change your ~/.bashrc. + +```bash +# In this example gem5 is located at $HOME/gem5_tnt/gem5. +export GEM5=$HOME/gem5_tnt/gem5 + +# Add the folder containing libgem5_opt.so to the list where libraries should +# be searched for. +#export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${GEM5}/build/ARM +export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${GEM5}/build/X86 +``` + +After that close QtCreator and all terminals. + +Open a new terminal. + Change the architecture in [DRAMSys/gem5/gem5.pro](DRAMSys/gem5/gem5.pro). ``` gem5_arch = 'X86' ``` -Make sure you have built **gem5/build/X86/libgem5_opt.so**. If you build with -[gem5.TnT] you can check if the library exists as follows. +Delete the file **DRAMSys/DRAMSys.pro.user** from the repository. ```bash -$ ls $HOME/gem5_tnt/gem5/build/X86/libgem5_opt.so +$ rm DRAMSys/DRAMSys.pro.user ``` +Open a new QtCreator. + Build DRAMSys as usual. After building, go the the folder where *DRAMSys_gem5* is located. From de8a546584b815d8bd06baf76dba313394057abe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Tue, 28 May 2019 12:22:30 +0200 Subject: [PATCH 62/97] improvement --- README.md | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 956d8b07..c805ea6b 100644 --- a/README.md +++ b/README.md @@ -1571,17 +1571,21 @@ Execute a hello world application: A **Hello world!** message should be printed to the standard output. -Execute a bubble sort application: +Execute applications: + +```bash +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/Oscar/config.ini 1 +``` ```bash ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/Bubblesort/config.ini 1 ``` -Wait some minutes for the bubble sort application to finish. +Wait some minutes for the application to finish. The hello application binary was copied from gem5 repository. -The bubble sort application was obtained with [gem5.TnT]. +Other applications were obtained with [gem5.TnT]. Command template for generating **.ini** configuration files follows: @@ -2091,6 +2095,24 @@ A **Hello world!** message should be printed to the standard output. Applications for x86 and configuration files available in [DRAMSys/gem5/gem5_se/MiBench](DRAMSys/gem5/gem5_se/MiBench). +Examples: + +```bash +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/network/dijkstra/small/config.ini 1 +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/network/dijkstra/large/config.ini 1 +``` + +```bash +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/network/patricia/small/config.ini 1 +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/network/patricia/large/config.ini 1 +``` + +```bash +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/basicmath/small/config.ini 1 +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/basicmath/large/config.ini 1 +``` + +Check the folder [DRAMSys/gem5/gem5_se/MiBench](DRAMSys/gem5/gem5_se/MiBench) for more applications. ## References From 963d65aecb1075030ae4adfb2d757d9b48a15cd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Tue, 28 May 2019 13:47:42 +0200 Subject: [PATCH 63/97] improvement --- README.md | 78 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 68 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index c805ea6b..af500ead 100644 --- a/README.md +++ b/README.md @@ -2097,22 +2097,80 @@ Applications for x86 and configuration files available in [DRAMSys/gem5/gem5_se/ Examples: -```bash -./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/network/dijkstra/small/config.ini 1 -./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/network/dijkstra/large/config.ini 1 -``` - -```bash -./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/network/patricia/small/config.ini 1 -./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/network/patricia/large/config.ini 1 -``` +**Automotive Applications** ```bash ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/basicmath/small/config.ini 1 ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/basicmath/large/config.ini 1 + +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/bitcount/small/config.ini 1 +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/bitcount/large/config.ini 1 + +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/qsort/small/config.ini 1 +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/qsort/large/config.ini 1 + +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/susan/small/corners/config.ini 1 +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/susan/small/edges/config.ini 1 +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/susan/small/smoothing/config.ini 1 + +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/susan/large/corners/config.ini 1 +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/susan/large/edges/config.ini 1 +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/susan/large/smoothing/config.ini 1 ``` -Check the folder [DRAMSys/gem5/gem5_se/MiBench](DRAMSys/gem5/gem5_se/MiBench) for more applications. +**Network Applications** + +```bash +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/network/dijkstra/small/config.ini 1 +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/network/dijkstra/large/config.ini 1 + +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/network/patricia/small/config.ini 1 +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/network/patricia/large/config.ini 1 +``` + +**Security Applications** + +**Blowfish Encode** +```bash +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/security/blowfish/encode/small/config.ini 1 +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/security/blowfish/encode/large/config.ini 1 +``` + +**Blowfish Decode** +```bash +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/security/blowfish/decode/small/config.ini 1 +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/security/blowfish/decode/large/config.ini 1 +``` + +```bash +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/security/sha/small/config.ini 1 +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/security/sha/large/config.ini 1 +``` + +**Telecom Applications** + +```bash +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/telecomm/crc32/small/config.ini 1 +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/telecomm/crc32/large/config.ini 1 +``` + +```bash +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/telecomm/fft/small/config.ini 1 +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/telecomm/fft/large/config.ini 1 + +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/telecomm/fft-inv/small/config.ini 1 +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/telecomm/fft-inv/large/config.ini 1 +``` + +```bash +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/telecomm/gsm/encode/small/config.ini 1 +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/telecomm/gsm/encode/large/config.ini 1 + +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/telecomm/gsm/decode/small/config.ini 1 +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/telecomm/gsm/decode/large/config.ini 1 +``` + +Check the folder [DRAMSys/gem5/gem5_se/MiBench](DRAMSys/gem5/gem5_se/MiBench) for all applications and configuration files. ## References From 5b46cbebe0a1f21b71508799e07588a6864f1960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Tue, 28 May 2019 14:04:48 +0200 Subject: [PATCH 64/97] improvement --- README.md | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index af500ead..dd7a338d 100644 --- a/README.md +++ b/README.md @@ -2099,31 +2099,46 @@ Examples: **Automotive Applications** +**Basicmath** ```bash ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/basicmath/small/config.ini 1 ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/basicmath/large/config.ini 1 +``` +**Bitcount** +```bash ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/bitcount/small/config.ini 1 ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/bitcount/large/config.ini 1 +``` +**Qsort** +```bash ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/qsort/small/config.ini 1 ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/qsort/large/config.ini 1 +``` +**Susan** +```bash ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/susan/small/corners/config.ini 1 -./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/susan/small/edges/config.ini 1 -./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/susan/small/smoothing/config.ini 1 - ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/susan/large/corners/config.ini 1 + +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/susan/small/edges/config.ini 1 ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/susan/large/edges/config.ini 1 + +./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/susan/small/smoothing/config.ini 1 ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/automotive/susan/large/smoothing/config.ini 1 ``` **Network Applications** +**Dijkstra** ```bash ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/network/dijkstra/small/config.ini 1 ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/network/dijkstra/large/config.ini 1 +``` +**Patricia** +```bash ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/network/patricia/small/config.ini 1 ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/network/patricia/large/config.ini 1 ``` @@ -2142,6 +2157,7 @@ Examples: ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/security/blowfish/decode/large/config.ini 1 ``` +**SHA** ```bash ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/security/sha/small/config.ini 1 ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/security/sha/large/config.ini 1 @@ -2149,23 +2165,32 @@ Examples: **Telecom Applications** +**CRC32** ```bash ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/telecomm/crc32/small/config.ini 1 ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/telecomm/crc32/large/config.ini 1 ``` +**FFT** ```bash ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/telecomm/fft/small/config.ini 1 ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/telecomm/fft/large/config.ini 1 +``` +**FFT-INV** +```bash ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/telecomm/fft-inv/small/config.ini 1 ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/telecomm/fft-inv/large/config.ini 1 ``` +**GSM Encode** ```bash ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/telecomm/gsm/encode/small/config.ini 1 ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/telecomm/gsm/encode/large/config.ini 1 +``` +**GSM Decode** +```bash ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/telecomm/gsm/decode/small/config.ini 1 ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/ddr3-gem5-se.xml ../../DRAMSys/gem5/gem5_se/MiBench/telecomm/gsm/decode/large/config.ini 1 ``` From b96121b4f84fb4f6a1cb08d01836f632f5e67254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Fri, 31 May 2019 16:44:19 +0200 Subject: [PATCH 65/97] improve --- README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/README.md b/README.md index dd7a338d..c23d501e 100644 --- a/README.md +++ b/README.md @@ -2197,6 +2197,35 @@ Examples: Check the folder [DRAMSys/gem5/gem5_se/MiBench](DRAMSys/gem5/gem5_se/MiBench) for all applications and configuration files. +### More AARCH64 Apps + +Full system simulation files for ARM available in [DRAMSys/gem5/gem5_fs/arm64](DRAMSys/gem5/gem5_fs/arm64). + +You can edit [arm64.rcS](DRAMSys/gem5/gem5_fs/arm64/arm64.rcS) to start an application and call *m5 exit* when it finishes. + +Edit the paths in [config.ini](DRAMSys/gem5/gem5_fs/arm64/config.ini). + +All files required to build DRAMSys_gem5 and execute the simulation (gem5 +library, benchmarks, disk image, etc.) can be obtained with [gem5.TnT]. + +Start a simulation. Example: + +```bash +dram.sys/build/gem5$ ./DRAMSys_gem5 ../../DRAMSys/library/resources/simulations/rgrsim-gem5-fs.xml ../../DRAMSys/gem5/gem5_fs/arm64/config.ini 1 +``` + +Optionally, open another terminal or tab and connect to gem5. + +```bash +$ telnet localhost 3456 +``` + +Note: the port may vary, gem5 prints it during initialization. Example: + +``` +system.terminal: Listening for connections on port 3456 +``` + ## References [1] TLM Modelling of 3D Stacked Wide I/O DRAM Subsystems, A Virtual Platform for Memory Controller Design Space Exploration From fb781882f789841cd3f50e41a8a65086cafb29c5 Mon Sep 17 00:00:00 2001 From: Lukas Steiner Laptop Date: Mon, 3 Jun 2019 15:42:50 +0200 Subject: [PATCH 66/97] Included doxygen config. --- .gitignore | 1 + DRAMSys/docs/doxyCfg.cfg | 1228 +++++++++++++++++++ DRAMSys/library/src/controller/Controller.h | 2 +- DRAMSys/library/src/simulation/Arbiter.h | 89 +- 4 files changed, 1278 insertions(+), 42 deletions(-) create mode 100644 DRAMSys/docs/doxyCfg.cfg diff --git a/.gitignore b/.gitignore index 02d40fb3..c7425d6f 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ DRAMSys/analyzer/scripts/__pycache__/ *.autosave *__pycache__* DRAMSys/gem5/boot_linux/linux-aarch32-ael.img +DRAMSys/docs/doxygen diff --git a/DRAMSys/docs/doxyCfg.cfg b/DRAMSys/docs/doxyCfg.cfg new file mode 100644 index 00000000..ea4940db --- /dev/null +++ b/DRAMSys/docs/doxyCfg.cfg @@ -0,0 +1,1228 @@ +# Doxyfile 1.4.4 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = DRAMSys + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = doxygen + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, +# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, +# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, +# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, +# Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# This tag can be used to specify the encoding used in the generated output. +# The encoding is not always determined by the language that is chosen, +# but also whether or not the output is meant for Windows or non-Windows users. +# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES +# forces the Windows encoding (this is the default for the Windows binary), +# whereas setting the tag to NO uses a Unix-style encoding (the default for +# all platforms other than Windows). + +USE_WINDOWS_ENCODING = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explicit @brief command for a brief description. + +JAVADOC_AUTOBRIEF = YES + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources +# only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is YES. + +SHOW_DIRECTORIES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from the +# version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the progam writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../ + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that a graph may be further truncated if the graph's +# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH +# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), +# the graph is not depth-constrained. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, which results in a white background. +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/DRAMSys/library/src/controller/Controller.h b/DRAMSys/library/src/controller/Controller.h index c309c02d..c911f996 100644 --- a/DRAMSys/library/src/controller/Controller.h +++ b/DRAMSys/library/src/controller/Controller.h @@ -78,7 +78,7 @@ using namespace tlm; DECLARE_EXTENDED_PHASE(PendingRequest); -class Controller: public sc_module, public IController +class Controller : public sc_module, public IController { public: Controller(sc_module_name /*name*/) : diff --git a/DRAMSys/library/src/simulation/Arbiter.h b/DRAMSys/library/src/simulation/Arbiter.h index 7f60913d..4881e664 100644 --- a/DRAMSys/library/src/simulation/Arbiter.h +++ b/DRAMSys/library/src/simulation/Arbiter.h @@ -54,7 +54,7 @@ using namespace std; using namespace tlm; -struct Arbiter: public sc_module { +struct Arbiter : public sc_module { public: tlm_utils::multi_passthrough_initiator_socket iSocket; tlm_utils::multi_passthrough_target_socket tSocket; @@ -66,7 +66,8 @@ public: // Anytime an transaction comes from a memory unity to the arbiter the "bw" callback is called. iSocket.register_nb_transport_bw(this, &Arbiter::nb_transport_bw); - for (size_t i = 0; i < Configuration::getInstance().NumberOfMemChannels; ++i) { + for (size_t i = 0; i < Configuration::getInstance().NumberOfMemChannels; ++i) + { channelIsFree.push_back(true); pendingRequests.push_back(queue()); } @@ -84,32 +85,16 @@ private: vector channelIsFree; - //used to account for the request_accept_delay in the dram controllers + // used to account for the request_accept_delay in the dram controllers // This is a queue of new transactions. The phase of a new request is BEGIN_REQ. vector> pendingRequests; - //used to account for the response_accept_delay in the initiators (traceplayer,core etc.) + // used to account for the response_accept_delay in the initiators (traceplayer, core etc.) // This is a queue of responses comming from the memory side. The phase of these transactions is BEGIN_RESP. std::map> receivedResponses; - //used to map the transaction from devices to the arbiter's target socket ID. + // used to map the transaction from devices to the arbiter's target socket ID. std::map routeMap; - // Initiated by dram side - // This function is called when an arbiter's initiator socket receives a transaction from a memory controller - tlm_sync_enum nb_transport_bw(int channelId, tlm_generic_payload &payload, - tlm_phase &phase, sc_time &bwDelay) - { - // Check channel ID - if ((unsigned int)channelId != DramExtension::getExtension( - payload).getChannel().ID()) { - SC_REPORT_FATAL("Arbiter", "Payload extension was corrupted"); - } - - printDebugMessage("[bw] " + phaseNameToString(phase) + " notification in " + - bwDelay.to_string()); - payloadEventQueue.notify(payload, phase, bwDelay); - return TLM_ACCEPTED; - } // Initiated by initiator side // This function is called when an arbiter's target socket receives a transaction from a device @@ -118,7 +103,8 @@ private: { sc_time notDelay = clkAlign(sc_time_stamp() + fwDelay) - (sc_time_stamp() + fwDelay); - if (phase == BEGIN_REQ) { + if (phase == BEGIN_REQ) + { // adjust address offset: payload.set_address(payload.get_address() - Configuration::getInstance().AddressOffset); @@ -130,7 +116,9 @@ private: // It will extracted from the payload and used later. appendDramExtension(id, payload); payload.acquire(); - } else if (phase == END_RESP) { + } + else if (phase == END_RESP) + { notDelay += Configuration::getInstance().memSpec.clk; // Erase before the payload is released. routeMap.erase(&payload); @@ -143,6 +131,21 @@ private: return TLM_ACCEPTED; } + // Initiated by dram side + // This function is called when an arbiter's initiator socket receives a transaction from a memory controller + tlm_sync_enum nb_transport_bw(int channelId, tlm_generic_payload &payload, + tlm_phase &phase, sc_time &bwDelay) + { + // Check channel ID + if ((unsigned int)channelId != DramExtension::getExtension(payload).getChannel().ID()) + SC_REPORT_FATAL("Arbiter", "Payload extension was corrupted"); + + printDebugMessage("[bw] " + phaseNameToString(phase) + " notification in " + + bwDelay.to_string()); + payloadEventQueue.notify(payload, phase, bwDelay); + return TLM_ACCEPTED; + } + virtual unsigned int transport_dbg(int /*id*/, tlm::tlm_generic_payload &trans) { // adjust address offset: @@ -164,7 +167,8 @@ private: assert(channelId < Configuration::getInstance().NumberOfMemChannels); // Phases initiated by the intiator side from arbiter's point of view (devices performing memory requests to the arbiter) - if (phase == BEGIN_REQ) { + if (phase == BEGIN_REQ) + { if (channelIsFree[channelId]) { // This channel was available. Forward the new transaction to the memory controller. channelIsFree[channelId] = false; @@ -173,21 +177,7 @@ private: // This channel is busy. Enqueue the new transaction which phase is BEGIN_REQ. pendingRequests[channelId].push(&payload); } - } else if (phase == END_RESP) { - // Send the END_RESP message to the memory - sendToChannel(channelId, payload, phase, SC_ZERO_TIME); - // Drop one element of the queue of BEGIN_RESP from memory to this device - receivedResponses[initiatorSocket].pop(); - - // Check if there are queued transactoins with phase BEGIN_RESP from memory to this device - if (!receivedResponses[initiatorSocket].empty()) { - // The queue is not empty. - tlm_generic_payload *payloadToSend = receivedResponses[initiatorSocket].front(); - // Send ONE extra BEGIN_RESP to the device - sendToInitiator(initiatorSocket, *payloadToSend, BEGIN_RESP, SC_ZERO_TIME); - } } - // Phases initiated by the target side from arbiter's point of view (memory side) else if (phase == END_REQ) { channelIsFree[channelId] = true; @@ -207,7 +197,9 @@ private: // Mark the channel as busy again. channelIsFree[channelId] = false; } - } else if (phase == BEGIN_RESP) { + } + else if (phase == BEGIN_RESP) + { // Validate the initiatorSocket ID if ((int)initiatorSocket != routeMap[&payload]) { SC_REPORT_FATAL("Arbiter", "Payload extension was corrupted"); @@ -221,10 +213,25 @@ private: // Enqueue the transaction in BEGIN_RESP phase until the initiator // device acknowledge it (phase changes to END_RESP). receivedResponses[initiatorSocket].push(&payload); - } else { + } + else if (phase == END_RESP) + { + // Send the END_RESP message to the memory + sendToChannel(channelId, payload, phase, SC_ZERO_TIME); + // Drop one element of the queue of BEGIN_RESP from memory to this device + receivedResponses[initiatorSocket].pop(); + + // Check if there are queued transactoins with phase BEGIN_RESP from memory to this device + if (!receivedResponses[initiatorSocket].empty()) { + // The queue is not empty. + tlm_generic_payload *payloadToSend = receivedResponses[initiatorSocket].front(); + // Send ONE extra BEGIN_RESP to the device + sendToInitiator(initiatorSocket, *payloadToSend, BEGIN_RESP, SC_ZERO_TIME); + } + } + else SC_REPORT_FATAL(0, "Payload event queue in arbiter was triggered with unknown phase"); - } } void sendToChannel(unsigned int channelId, tlm_generic_payload &payload, From b90784f54c9f4488d5e940ef2717e5910fb16b64 Mon Sep 17 00:00:00 2001 From: "Lukas Steiner (2)" Date: Tue, 4 Jun 2019 15:51:35 +0200 Subject: [PATCH 67/97] Created cpp file for arbiter. Removed redundant routing table in arbiter. --- DRAMSys/library/library.pro | 3 +- DRAMSys/library/src/simulation/Arbiter.cpp | 250 ++++++++++++++++++ DRAMSys/library/src/simulation/Arbiter.h | 222 +--------------- DRAMSys/library/src/simulation/StlPlayer.h | 10 +- .../library/src/simulation/TracePlayer.cpp | 11 +- DRAMSys/library/src/simulation/TracePlayer.h | 7 +- DRAMSys/library/src/simulation/TraceSetup.cpp | 13 +- 7 files changed, 287 insertions(+), 229 deletions(-) create mode 100644 DRAMSys/library/src/simulation/Arbiter.cpp diff --git a/DRAMSys/library/library.pro b/DRAMSys/library/library.pro index 113fe07d..a1c1b07a 100644 --- a/DRAMSys/library/library.pro +++ b/DRAMSys/library/library.pro @@ -143,7 +143,8 @@ SOURCES += \ src/controller/RecordableController.cpp \ src/common/AddressDecoder.cpp \ src/controller/scheduler/grp.cpp \ - src/common/congenAddressDecoder.cpp + src/common/congenAddressDecoder.cpp \ + src/simulation/Arbiter.cpp HEADERS += \ src/common/third_party/tinyxml2/tinyxml2.h \ diff --git a/DRAMSys/library/src/simulation/Arbiter.cpp b/DRAMSys/library/src/simulation/Arbiter.cpp new file mode 100644 index 00000000..f417eb1e --- /dev/null +++ b/DRAMSys/library/src/simulation/Arbiter.cpp @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2015, University of Kaiserslautern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: + * Robert Gernhardt + * Matthias Jung + * Eder F. Zulian + */ + +#include "Arbiter.h" + +using namespace std; +using namespace tlm; + +Arbiter::Arbiter(sc_module_name) : payloadEventQueue(this, &Arbiter::peqCallback) +{ + // The arbiter communicates with one or more memory unity through one or more sockets (one or more memory channels). + // Each of the arbiter's initiator sockets is bound to a memory controller's target socket. + // Anytime an transaction comes from a memory unity to the arbiter the "bw" callback is called. + iSocket.register_nb_transport_bw(this, &Arbiter::nb_transport_bw); + + for (size_t i = 0; i < Configuration::getInstance().NumberOfMemChannels; ++i) + { + channelIsFree.push_back(true); + pendingRequests.push_back(queue()); + } + + // One or more devices can accesss all the memory units through the arbiter. + // Devices' initiator sockets are bound to arbiter's target sockets. + // As soon the arbiter receives a request in any of its target sockets it should treat and forward it to the proper memory channel. + tSocket.register_nb_transport_fw(this, &Arbiter::nb_transport_fw); + + tSocket.register_transport_dbg(this, &Arbiter::transport_dbg); +} + +// Initiated by initiator side +// This function is called when an arbiter's target socket receives a transaction from a device +tlm_sync_enum Arbiter::nb_transport_fw(int id, tlm_generic_payload &payload, + tlm_phase &phase, sc_time &fwDelay) +{ + sc_time notDelay = clkAlign(sc_time_stamp() + fwDelay) - + (sc_time_stamp() + fwDelay); + if (phase == BEGIN_REQ) + { + // adjust address offset: + payload.set_address(payload.get_address() - + Configuration::getInstance().AddressOffset); + + // In the begin request phase the socket ID is appended to the payload. + // It will extracted from the payload and used later. + appendDramExtension(id, payload); + payload.acquire(); + } + else if (phase == END_RESP) + { + notDelay += Configuration::getInstance().memSpec.clk; + payload.release(); + } + + printDebugMessage("[fw] " + phaseNameToString(phase) + " notification in " + + notDelay.to_string()); + payloadEventQueue.notify(payload, phase, notDelay); + return TLM_ACCEPTED; +} + +// Initiated by dram side +// This function is called when an arbiter's initiator socket receives a transaction from a memory controller +tlm_sync_enum Arbiter::nb_transport_bw(int channelId, tlm_generic_payload &payload, + tlm_phase &phase, sc_time &bwDelay) +{ + // Check channel ID + if ((unsigned int)channelId != DramExtension::getExtension(payload).getChannel().ID()) + SC_REPORT_FATAL("Arbiter", "Payload extension was corrupted"); + + printDebugMessage("[bw] " + phaseNameToString(phase) + " notification in " + + bwDelay.to_string()); + payloadEventQueue.notify(payload, phase, bwDelay); + return TLM_ACCEPTED; +} + +unsigned int Arbiter::transport_dbg(int /*id*/, tlm::tlm_generic_payload &trans) +{ + // adjust address offset: + trans.set_address(trans.get_address() - + Configuration::getInstance().AddressOffset); + + DecodedAddress decodedAddress = AddressDecoder::getInstance().decodeAddress( + trans.get_address()); + return iSocket[decodedAddress.channel]->transport_dbg(trans); +} + +void Arbiter::peqCallback(tlm_generic_payload &payload, const tlm_phase &phase) +{ + unsigned int initiatorSocket = DramExtension::getExtension( + payload).getThread().ID(); + unsigned int channelId = DramExtension::getExtension(payload).getChannel().ID(); + + // Check the valid range of initiatorSocket ID and channel Id + assert(channelId < Configuration::getInstance().NumberOfMemChannels); + + // Phases initiated by the intiator side from arbiter's point of view (devices performing memory requests to the arbiter) + if (phase == BEGIN_REQ) + { + if (channelIsFree[channelId]) { + // This channel was available. Forward the new transaction to the memory controller. + channelIsFree[channelId] = false; + sendToChannel(channelId, payload, phase, SC_ZERO_TIME); + } else { + // This channel is busy. Enqueue the new transaction which phase is BEGIN_REQ. + pendingRequests[channelId].push(&payload); + } + } + // Phases initiated by the target side from arbiter's point of view (memory side) + else if (phase == END_REQ) { + channelIsFree[channelId] = true; + + // The arbiter receives a transaction which phase is END_REQ from memory controller and forwards it to the requester device. + sendToInitiator(initiatorSocket, payload, phase, SC_ZERO_TIME); + + // This channel is now free! Dispatch a new transaction (phase is BEGIN_REQ) from the queue, if any. Send it to the memory controller. + if (!pendingRequests[channelId].empty()) { + tlm_generic_payload *payloadToSend = pendingRequests[channelId].front(); + pendingRequests[channelId].pop(); + // Send ONE of the enqueued new transactions (phase is BEGIN_REQ) through this channel. + sendToChannel(channelId, *payloadToSend, BEGIN_REQ, SC_ZERO_TIME); + // Mark the channel as busy again. + channelIsFree[channelId] = false; + } + } + else if (phase == BEGIN_RESP) + { + // The arbiter receives a transaction in BEGIN_RESP phase + // (that came from the memory side) and forwards it to the requester + // device + if (receivedResponses[initiatorSocket].empty()) { + sendToInitiator(initiatorSocket, payload, phase, SC_ZERO_TIME); + } + // Enqueue the transaction in BEGIN_RESP phase until the initiator + // device acknowledge it (phase changes to END_RESP). + receivedResponses[initiatorSocket].push(&payload); + } + else if (phase == END_RESP) + { + // Send the END_RESP message to the memory + sendToChannel(channelId, payload, phase, SC_ZERO_TIME); + // Drop one element of the queue of BEGIN_RESP from memory to this device + receivedResponses[initiatorSocket].pop(); + + // Check if there are queued transactoins with phase BEGIN_RESP from memory to this device + if (!receivedResponses[initiatorSocket].empty()) { + // The queue is not empty. + tlm_generic_payload *payloadToSend = receivedResponses[initiatorSocket].front(); + // Send ONE extra BEGIN_RESP to the device + sendToInitiator(initiatorSocket, *payloadToSend, BEGIN_RESP, SC_ZERO_TIME); + } + } + else + SC_REPORT_FATAL(0, + "Payload event queue in arbiter was triggered with unknown phase"); +} + +void Arbiter::sendToChannel(unsigned int channelId, tlm_generic_payload &payload, + const tlm_phase &phase, const sc_time &delay) +{ + tlm_phase TPhase = phase; + sc_time TDelay = delay; + iSocket[channelId]->nb_transport_fw(payload, TPhase, TDelay); +} + +void Arbiter::sendToInitiator(unsigned int id, tlm_generic_payload &payload, + const tlm_phase &phase, const sc_time &delay) +{ + tlm_phase TPhase = phase; + sc_time TDelay = delay; + tSocket[id]->nb_transport_bw(payload, TPhase, TDelay); +} + +void Arbiter::appendDramExtension(int socketId, tlm_generic_payload &payload) +{ + // Append Generation Extension + GenerationExtension *genExtension = new GenerationExtension(sc_time_stamp()); + payload.set_auto_extension(genExtension); + + unsigned int burstlength = payload.get_streaming_width(); + DecodedAddress decodedAddress = AddressDecoder::getInstance().decodeAddress(payload.get_address()); + // Check the valid range of decodedAddress + if (addressIsValid(decodedAddress)) { + DramExtension *extension = new DramExtension(Thread(socketId), + Channel(decodedAddress.channel), Bank(decodedAddress.bank), + BankGroup(decodedAddress.bankgroup), Row(decodedAddress.row), + Column(decodedAddress.column), burstlength); + payload.set_auto_extension(extension); + } else { + SC_REPORT_FATAL("Arbiter", "Decoded Address is not inside the valid range"); + } +} + +bool Arbiter::addressIsValid(DecodedAddress &decodedAddress) +{ + if (decodedAddress.channel >= AddressDecoder::getInstance().amount["channel"]) { + return false; + } + if (decodedAddress.bank >= AddressDecoder::getInstance().amount["bank"]) { + return false; + } + if (decodedAddress.bankgroup > + AddressDecoder::getInstance().amount["bankgroup"]) { + return false; + } + if (decodedAddress.column >= AddressDecoder::getInstance().amount["column"]) { + return false; + } + if (decodedAddress.row >= AddressDecoder::getInstance().amount["row"]) { + return false; + } + return true; +} + +void Arbiter::printDebugMessage(std::string message) +{ + DebugManager::getInstance().printDebugMessage(this->name(), message); +} diff --git a/DRAMSys/library/src/simulation/Arbiter.h b/DRAMSys/library/src/simulation/Arbiter.h index 4881e664..1c5687b0 100644 --- a/DRAMSys/library/src/simulation/Arbiter.h +++ b/DRAMSys/library/src/simulation/Arbiter.h @@ -54,31 +54,14 @@ using namespace std; using namespace tlm; -struct Arbiter : public sc_module { +class Arbiter : public sc_module +{ public: tlm_utils::multi_passthrough_initiator_socket iSocket; tlm_utils::multi_passthrough_target_socket tSocket; - SC_CTOR(Arbiter) : payloadEventQueue(this, &Arbiter::peqCallback) - { - // The arbiter communicates with one or more memory unity through one or more sockets (one or more memory channels). - // Each of the arbiter's initiator sockets is bound to a memory controller's target socket. - // Anytime an transaction comes from a memory unity to the arbiter the "bw" callback is called. - iSocket.register_nb_transport_bw(this, &Arbiter::nb_transport_bw); - - for (size_t i = 0; i < Configuration::getInstance().NumberOfMemChannels; ++i) - { - channelIsFree.push_back(true); - pendingRequests.push_back(queue()); - } - - // One or more devices can accesss all the memory units through the arbiter. - // Devices' initiator sockets are bound to arbiter's target sockets. - // As soon the arbiter receives a request in any of its target sockets it should treat and forward it to the proper memory channel. - tSocket.register_nb_transport_fw(this, &Arbiter::nb_transport_fw); - - tSocket.register_transport_dbg(this, &Arbiter::transport_dbg); - } + Arbiter(sc_module_name); + SC_HAS_PROCESS(Arbiter); private: tlm_utils::peq_with_cb_and_phase payloadEventQueue; @@ -92,210 +75,31 @@ private: // This is a queue of responses comming from the memory side. The phase of these transactions is BEGIN_RESP. std::map> receivedResponses; - // used to map the transaction from devices to the arbiter's target socket ID. - std::map routeMap; - - // Initiated by initiator side // This function is called when an arbiter's target socket receives a transaction from a device tlm_sync_enum nb_transport_fw(int id, tlm_generic_payload &payload, - tlm_phase &phase, sc_time &fwDelay) - { - sc_time notDelay = clkAlign(sc_time_stamp() + fwDelay) - - (sc_time_stamp() + fwDelay); - if (phase == BEGIN_REQ) - { - // adjust address offset: - payload.set_address(payload.get_address() - - Configuration::getInstance().AddressOffset); - - // Map the payload with socket id. - routeMap[&payload] = id; - - // In the begin request phase the socket ID is appended to the payload. - // It will extracted from the payload and used later. - appendDramExtension(id, payload); - payload.acquire(); - } - else if (phase == END_RESP) - { - notDelay += Configuration::getInstance().memSpec.clk; - // Erase before the payload is released. - routeMap.erase(&payload); - payload.release(); - } - - printDebugMessage("[fw] " + phaseNameToString(phase) + " notification in " + - notDelay.to_string()); - payloadEventQueue.notify(payload, phase, notDelay); - return TLM_ACCEPTED; - } + tlm_phase &phase, sc_time &fwDelay); // Initiated by dram side // This function is called when an arbiter's initiator socket receives a transaction from a memory controller tlm_sync_enum nb_transport_bw(int channelId, tlm_generic_payload &payload, - tlm_phase &phase, sc_time &bwDelay) - { - // Check channel ID - if ((unsigned int)channelId != DramExtension::getExtension(payload).getChannel().ID()) - SC_REPORT_FATAL("Arbiter", "Payload extension was corrupted"); + tlm_phase &phase, sc_time &bwDelay); - printDebugMessage("[bw] " + phaseNameToString(phase) + " notification in " + - bwDelay.to_string()); - payloadEventQueue.notify(payload, phase, bwDelay); - return TLM_ACCEPTED; - } + virtual unsigned int transport_dbg(int /*id*/, tlm::tlm_generic_payload &trans); - virtual unsigned int transport_dbg(int /*id*/, tlm::tlm_generic_payload &trans) - { - // adjust address offset: - trans.set_address(trans.get_address() - - Configuration::getInstance().AddressOffset); - - DecodedAddress decodedAddress = AddressDecoder::getInstance().decodeAddress( - trans.get_address()); - return iSocket[decodedAddress.channel]->transport_dbg(trans); - } - - void peqCallback(tlm_generic_payload &payload, const tlm_phase &phase) - { - unsigned int initiatorSocket = DramExtension::getExtension( - payload).getThread().ID(); - unsigned int channelId = DramExtension::getExtension(payload).getChannel().ID(); - - // Check the valid range of initiatorSocket ID and channel Id - assert(channelId < Configuration::getInstance().NumberOfMemChannels); - - // Phases initiated by the intiator side from arbiter's point of view (devices performing memory requests to the arbiter) - if (phase == BEGIN_REQ) - { - if (channelIsFree[channelId]) { - // This channel was available. Forward the new transaction to the memory controller. - channelIsFree[channelId] = false; - sendToChannel(channelId, payload, phase, SC_ZERO_TIME); - } else { - // This channel is busy. Enqueue the new transaction which phase is BEGIN_REQ. - pendingRequests[channelId].push(&payload); - } - } - // Phases initiated by the target side from arbiter's point of view (memory side) - else if (phase == END_REQ) { - channelIsFree[channelId] = true; - // Validate the initiatorSocket ID - if ((int)initiatorSocket != routeMap[&payload]) { - SC_REPORT_FATAL("Arbiter", "Payload extension was corrupted"); - } - // The arbiter receives a transaction which phase is END_REQ from memory controller and forwards it to the requester device. - sendToInitiator(initiatorSocket, payload, phase, SC_ZERO_TIME); - - // This channel is now free! Dispatch a new transaction (phase is BEGIN_REQ) from the queue, if any. Send it to the memory controller. - if (!pendingRequests[channelId].empty()) { - tlm_generic_payload *payloadToSend = pendingRequests[channelId].front(); - pendingRequests[channelId].pop(); - // Send ONE of the enqueued new transactions (phase is BEGIN_REQ) through this channel. - sendToChannel(channelId, *payloadToSend, BEGIN_REQ, SC_ZERO_TIME); - // Mark the channel as busy again. - channelIsFree[channelId] = false; - } - } - else if (phase == BEGIN_RESP) - { - // Validate the initiatorSocket ID - if ((int)initiatorSocket != routeMap[&payload]) { - SC_REPORT_FATAL("Arbiter", "Payload extension was corrupted"); - } - // The arbiter receives a transaction in BEGIN_RESP phase - // (that came from the memory side) and forwards it to the requester - // device - if (receivedResponses[initiatorSocket].empty()) { - sendToInitiator(initiatorSocket, payload, phase, SC_ZERO_TIME); - } - // Enqueue the transaction in BEGIN_RESP phase until the initiator - // device acknowledge it (phase changes to END_RESP). - receivedResponses[initiatorSocket].push(&payload); - } - else if (phase == END_RESP) - { - // Send the END_RESP message to the memory - sendToChannel(channelId, payload, phase, SC_ZERO_TIME); - // Drop one element of the queue of BEGIN_RESP from memory to this device - receivedResponses[initiatorSocket].pop(); - - // Check if there are queued transactoins with phase BEGIN_RESP from memory to this device - if (!receivedResponses[initiatorSocket].empty()) { - // The queue is not empty. - tlm_generic_payload *payloadToSend = receivedResponses[initiatorSocket].front(); - // Send ONE extra BEGIN_RESP to the device - sendToInitiator(initiatorSocket, *payloadToSend, BEGIN_RESP, SC_ZERO_TIME); - } - } - else - SC_REPORT_FATAL(0, - "Payload event queue in arbiter was triggered with unknown phase"); - } + void peqCallback(tlm_generic_payload &payload, const tlm_phase &phase); void sendToChannel(unsigned int channelId, tlm_generic_payload &payload, - const tlm_phase &phase, const sc_time &delay) - { - tlm_phase TPhase = phase; - sc_time TDelay = delay; - iSocket[channelId]->nb_transport_fw(payload, TPhase, TDelay); - } + const tlm_phase &phase, const sc_time &delay); void sendToInitiator(unsigned int id, tlm_generic_payload &payload, - const tlm_phase &phase, const sc_time &delay) - { - tlm_phase TPhase = phase; - sc_time TDelay = delay; - tSocket[id]->nb_transport_bw(payload, TPhase, TDelay); - } + const tlm_phase &phase, const sc_time &delay); - void appendDramExtension(int socketId, tlm_generic_payload &payload) - { - // Append Generation Extension - GenerationExtension *genExtension = new GenerationExtension(sc_time_stamp()); - payload.set_auto_extension(genExtension); + void appendDramExtension(int socketId, tlm_generic_payload &payload); - unsigned int burstlength = payload.get_streaming_width(); - DecodedAddress decodedAddress = AddressDecoder::getInstance().decodeAddress( - payload.get_address()); - // Check the valid range of decodedAddress - if (addressIsValid(decodedAddress)) { - DramExtension *extension = new DramExtension(Thread(socketId), - Channel(decodedAddress.channel), Bank(decodedAddress.bank), - BankGroup(decodedAddress.bankgroup), Row(decodedAddress.row), - Column(decodedAddress.column), burstlength); - payload.set_auto_extension(extension); - } else { - SC_REPORT_FATAL("Arbiter", "Decoded Address are not inside the valid range"); - } - } + bool addressIsValid(DecodedAddress &decodedAddress); - bool addressIsValid(DecodedAddress &decodedAddress) - { - if (decodedAddress.channel >= AddressDecoder::getInstance().amount["channel"]) { - return false; - } - if (decodedAddress.bank >= AddressDecoder::getInstance().amount["bank"]) { - return false; - } - if (decodedAddress.bankgroup > - AddressDecoder::getInstance().amount["bankgroup"]) { - return false; - } - if (decodedAddress.column >= AddressDecoder::getInstance().amount["column"]) { - return false; - } - if (decodedAddress.row >= AddressDecoder::getInstance().amount["row"]) { - return false; - } - return true; - } - - void printDebugMessage(std::string message) - { - DebugManager::getInstance().printDebugMessage(this->name(), message); - } + void printDebugMessage(std::string message); }; #endif /* ARBITER_H_ */ diff --git a/DRAMSys/library/src/simulation/StlPlayer.h b/DRAMSys/library/src/simulation/StlPlayer.h index 8e36b54b..ee5ac0a0 100644 --- a/DRAMSys/library/src/simulation/StlPlayer.h +++ b/DRAMSys/library/src/simulation/StlPlayer.h @@ -86,7 +86,6 @@ public: } else { numberOfTransactions++; } - // Allocate a generic payload for this request. gp *payload = this->allocatePayload(); @@ -170,16 +169,17 @@ public: payload->set_data_ptr(data); payload->set_command(cmd); - if (relative == false) { + if (relative == false) + { // Send the transaction directly or schedule it to be sent in the future. if (sendingTime <= sc_time_stamp()) this->payloadEventQueue.notify(*payload, BEGIN_REQ, SC_ZERO_TIME); else this->payloadEventQueue.notify(*payload, BEGIN_REQ, sendingTime - sc_time_stamp()); - } else { - payloadEventQueue.notify(*payload, BEGIN_REQ, sendingTime); } + else + payloadEventQueue.notify(*payload, BEGIN_REQ, sendingTime); } private: @@ -188,7 +188,7 @@ private: unsigned int burstlength; unsigned int dataLength; - sc_time playerClk; // May be different from from the memory clock! + sc_time playerClk; // May be different from the memory clock! }; #endif // STLPLAYER_H diff --git a/DRAMSys/library/src/simulation/TracePlayer.cpp b/DRAMSys/library/src/simulation/TracePlayer.cpp index e46840b3..793dd904 100644 --- a/DRAMSys/library/src/simulation/TracePlayer.cpp +++ b/DRAMSys/library/src/simulation/TracePlayer.cpp @@ -80,7 +80,6 @@ tlm_sync_enum TracePlayer::nb_transport_bw(tlm_generic_payload &payload, void TracePlayer::peqCallback(tlm_generic_payload &payload, const tlm_phase &phase) { - if (phase == BEGIN_REQ) { payload.acquire(); sendToTarget(payload, phase, SC_ZERO_TIME); @@ -99,7 +98,8 @@ void TracePlayer::peqCallback(tlm_generic_payload &payload, transactionsReceived++; // If all answers were received: - if (finished == true && numberOfTransactions == transactionsReceived) { + if (finished == true && numberOfTransactions == transactionsReceived) + { this->terminate(); } } else if (phase == END_RESP) { @@ -108,6 +108,13 @@ void TracePlayer::peqCallback(tlm_generic_payload &payload, } } +void TracePlayer::sendToTarget(tlm_generic_payload &payload, const tlm_phase &phase, const sc_time &delay) +{ + tlm_phase TPhase = phase; + sc_time TDelay = delay; + iSocket->nb_transport_fw(payload, TPhase, TDelay); +} + void TracePlayer::setNumberOfTransactions(unsigned int n) { numberOfTransactions = n; diff --git a/DRAMSys/library/src/simulation/TracePlayer.h b/DRAMSys/library/src/simulation/TracePlayer.h index d03f5ead..dd4cb8ae 100644 --- a/DRAMSys/library/src/simulation/TracePlayer.h +++ b/DRAMSys/library/src/simulation/TracePlayer.h @@ -77,12 +77,7 @@ private: sc_time &bwDelay); void peqCallback(tlm_generic_payload &payload, const tlm_phase &phase); void sendToTarget(tlm_generic_payload &payload, const tlm_phase &phase, - const sc_time &delay) - { - tlm_phase TPhase = phase; - sc_time TDelay = delay; - iSocket->nb_transport_fw(payload, TPhase, TDelay); - } + const sc_time &delay); MemoryManager memoryManager; unsigned int transactionsSent; unsigned int transactionsReceived; diff --git a/DRAMSys/library/src/simulation/TraceSetup.cpp b/DRAMSys/library/src/simulation/TraceSetup.cpp index c64eac3d..79a241d6 100644 --- a/DRAMSys/library/src/simulation/TraceSetup.cpp +++ b/DRAMSys/library/src/simulation/TraceSetup.cpp @@ -56,9 +56,10 @@ traceSetup::traceSetup(std::string uri, simulation->FirstChildElement("tracesetup"); for (tinyxml2::XMLElement *device = - tracesetup->FirstChildElement("device"); - device != NULL; - device = device->NextSiblingElement("device")) { + tracesetup->FirstChildElement("device"); + device != NULL; + device = device->NextSiblingElement("device")) + { sc_time playerClk; unsigned int frequency = device->IntAttribute("clkMhz"); @@ -83,12 +84,12 @@ traceSetup::traceSetup(std::string uri, std::string moduleName = name; // replace all '.' to '_' - std::replace( moduleName.begin(), moduleName.end(), '.', '_'); + std::replace(moduleName.begin(), moduleName.end(), '.', '_'); TracePlayer *player; - if (strcmp(ext.c_str(), "stl") == 0) { + if (ext == "stl") { player = new StlPlayer(moduleName.c_str(), stlFile, playerClk, this); - } else if (strcmp(ext.c_str(), "rstl") == 0) { + } else if (ext == "rstl") { player = new StlPlayer(moduleName.c_str(), stlFile, playerClk, this); } else { std::string error = "Unsupported file extension in " + name; From 84bd62a781fdc7d1b3f4301ef94405246a330d10 Mon Sep 17 00:00:00 2001 From: "Lukas Steiner (2)" Date: Wed, 5 Jun 2019 16:21:26 +0200 Subject: [PATCH 68/97] No changes, some TODOs for future work. --- .../resources/configs/simulator/ddr3.xml | 2 +- DRAMSys/library/src/controller/Controller.cpp | 51 ++++++++++++------- DRAMSys/library/src/controller/Controller.h | 6 +-- .../library/src/controller/scheduler/Fifo.cpp | 19 +++---- .../library/src/controller/scheduler/Fifo.h | 7 +-- .../src/controller/scheduler/FifoStrict.cpp | 8 +-- .../src/controller/scheduler/FifoStrict.h | 2 +- DRAMSys/library/src/simulation/Arbiter.cpp | 4 +- DRAMSys/library/src/simulation/DRAMSys.cpp | 2 +- coding-style.md | 2 +- 10 files changed, 61 insertions(+), 42 deletions(-) diff --git a/DRAMSys/library/resources/configs/simulator/ddr3.xml b/DRAMSys/library/resources/configs/simulator/ddr3.xml index 1613737f..f43e4b8c 100644 --- a/DRAMSys/library/resources/configs/simulator/ddr3.xml +++ b/DRAMSys/library/resources/configs/simulator/ddr3.xml @@ -1,6 +1,6 @@ - + diff --git a/DRAMSys/library/src/controller/Controller.cpp b/DRAMSys/library/src/controller/Controller.cpp index ebe31027..dfc021ba 100644 --- a/DRAMSys/library/src/controller/Controller.cpp +++ b/DRAMSys/library/src/controller/Controller.cpp @@ -232,12 +232,14 @@ tlm_sync_enum Controller::nb_transport_fw(tlm_generic_payload &payload, if (phase == BEGIN_REQ) { notDelay += Configuration::getInstance().memSpec.clk; - //Bandwidth IDLE + // Bandwidth IDLE if ((getTotalNumberOfPayloadsInSystem() == 0) && idleState) { endBandwidthIdleCollector(); } - } else if (phase == END_RESP) { - // Badnwith IDLE + } + else if (phase == END_RESP) { + // Bandwidth IDLE + // TODO: getTotalNumberOfPayloadsInSystem() == 1 && !idleState ?? if (getTotalNumberOfPayloadsInSystem() == 1) { startBandwidthIdleCollector(); } @@ -258,13 +260,15 @@ unsigned int Controller::transport_dbg(tlm::tlm_generic_payload &trans) void Controller::frontendPEQCallback(tlm_generic_payload &payload, const tlm_phase &phase) { - if (phase == BEGIN_REQ) { - printDebugMessage(string("Payload in system: ") + to_string( - getTotalNumberOfPayloadsInSystem())); + if (phase == BEGIN_REQ) + { + printDebugMessage(string("Payload in system: ") + + to_string(getTotalNumberOfPayloadsInSystem())); payload.acquire(); payloadEntersSystem(payload); if (getTotalNumberOfPayloadsInSystem() > - controllerCore->config.MaxNrOfTransactions) { + controllerCore->config.MaxNrOfTransactions) + { printDebugMessage("##Backpressure: Max number of transactions in system reached"); backpressure = &payload; return; @@ -273,12 +277,18 @@ void Controller::frontendPEQCallback(tlm_generic_payload &payload, sendToFrontend(payload, END_REQ, SC_ZERO_TIME); scheduler->storeRequest(&payload); + // TODO: (current position in code) scheduleNextFromScheduler(DramExtension::getExtension(payload).getBank()); - } else if (phase == PendingRequest) { + } + else if (phase == PendingRequest) + { // Schedule a pending request. scheduleNextFromScheduler(DramExtension::getExtension(payload).getBank()); - } else if (phase == END_RESP) { - if (backpressure != NULL) { + } + else if (phase == END_RESP) + { + if (backpressure != NULL) + { printDebugMessage("##Backpressure released"); backpressure->set_response_status(tlm::TLM_OK_RESPONSE); sendToFrontend(*backpressure, END_REQ, SC_ZERO_TIME); @@ -292,11 +302,11 @@ void Controller::frontendPEQCallback(tlm_generic_payload &payload, responseQueue.pop(); payload.release(); - if(!responseQueue.empty()) { + if(!responseQueue.empty()) sendToFrontend(*(responseQueue.front()), BEGIN_RESP, SC_ZERO_TIME); - } - - } else { + } + else + { SC_REPORT_FATAL(0, "Front-end PEQ in controller wrapper was triggered with unknown phase"); } @@ -305,12 +315,14 @@ void Controller::frontendPEQCallback(tlm_generic_payload &payload, void Controller::payloadEntersSystem(tlm_generic_payload &payload) { Bank bank = DramExtension::getExtension(payload).getBank(); + // TODO: first increase numberOfPayloadsInSystem[bank], then printDebugMessage ?? printDebugMessage( "Payload enters system on bank " + to_string(bank.ID()) + ". Total number of payloads in Controller: " + to_string(getTotalNumberOfPayloadsInSystem())); numberOfPayloadsInSystem[bank]++; // Set Start Time for Simulation + // TODO: startTimeSet always false at this point?? if (startTimeSet == false) { printDebugMessage("Simulation Timer Start"); startTime = sc_time_stamp() - Configuration::getInstance().memSpec.clk; @@ -340,18 +352,21 @@ unsigned int Controller::getTotalNumberOfPayloadsInSystem() void Controller::scheduleNextFromScheduler(Bank bank) { - if (controllerCore->bankIsBusy(bank)) { + if (controllerCore->bankIsBusy(bank)) return; - } bool rescheduled = true; pair nextRequest = scheduler->getNextRequest(bank); if (nextRequest.second != NULL) { schedule(nextRequest.first, *nextRequest.second); - } else { + } + else + { + // TODO: getPendingRequest is only used by SMS scheduler gp *pendingRequest = scheduler->getPendingRequest(bank); - if (pendingRequest != NULL) { + if (pendingRequest != NULL) + { rescheduled = true; frontendPEQ.notify(*(pendingRequest), PendingRequest, Configuration::getInstance().memSpec.clk); diff --git a/DRAMSys/library/src/controller/Controller.h b/DRAMSys/library/src/controller/Controller.h index c911f996..7e524a51 100644 --- a/DRAMSys/library/src/controller/Controller.h +++ b/DRAMSys/library/src/controller/Controller.h @@ -82,9 +82,9 @@ class Controller : public sc_module, public IController { public: Controller(sc_module_name /*name*/) : - frontendPEQ(this, &Controller::frontendPEQCallback), dramPEQ(this, - &Controller::dramPEQCallback), controllerCorePEQ(this, - &Controller::controllerCorePEQCallback), + frontendPEQ(this, &Controller::frontendPEQCallback), + dramPEQ(this, &Controller::dramPEQCallback), + controllerCorePEQ(this, &Controller::controllerCorePEQCallback), debugManager(DebugManager::getInstance()) { controllerCore = new ControllerCore("core", *this, numberOfPayloadsInSystem); diff --git a/DRAMSys/library/src/controller/scheduler/Fifo.cpp b/DRAMSys/library/src/controller/scheduler/Fifo.cpp index 6eb46aa8..305e2798 100644 --- a/DRAMSys/library/src/controller/scheduler/Fifo.cpp +++ b/DRAMSys/library/src/controller/scheduler/Fifo.cpp @@ -36,27 +36,28 @@ #include "Fifo.h" -using namespace std; - void Fifo::storeRequest(gp *payload) { - buffer[DramExtension::getExtension(payload).getBank()].emplace_back(payload); + Bank bank = DramExtension::getExtension(payload).getBank(); + buffer[bank].emplace_back(payload); } -pair Fifo::getNextRequest(Bank bank) +std::pair Fifo::getNextRequest(Bank bank) { - if (!buffer[bank].empty()) { + if (!buffer[bank].empty()) + { gp *payload = buffer[bank].front(); Command command = IScheduler::getNextCommand(*payload); if (command == Command::Read || command == Command::ReadA - || command == Command::Write || command == Command::WriteA) { + || command == Command::Write || command == Command::WriteA) + { buffer[bank].pop_front(); } - return pair(command, payload); + return std::pair(command, payload); } - - return pair(Command::NOP, NULL); + else + return std::pair(Command::NOP, NULL); } gp *Fifo::getPendingRequest(Bank /*bank*/) diff --git a/DRAMSys/library/src/controller/scheduler/Fifo.h b/DRAMSys/library/src/controller/scheduler/Fifo.h index 912570d2..dfb5820c 100644 --- a/DRAMSys/library/src/controller/scheduler/Fifo.h +++ b/DRAMSys/library/src/controller/scheduler/Fifo.h @@ -37,13 +37,14 @@ #ifndef FIFO_H_ #define FIFO_H_ -#include "../core/ControllerCore.h" -#include "../Command.h" -#include "IScheduler.h" #include #include #include +#include "../core/ControllerCore.h" +#include "../Command.h" +#include "IScheduler.h" + class Fifo : public IScheduler { public: diff --git a/DRAMSys/library/src/controller/scheduler/FifoStrict.cpp b/DRAMSys/library/src/controller/scheduler/FifoStrict.cpp index 9b3f8ec3..3f36dd9e 100644 --- a/DRAMSys/library/src/controller/scheduler/FifoStrict.cpp +++ b/DRAMSys/library/src/controller/scheduler/FifoStrict.cpp @@ -92,7 +92,7 @@ std::pair FifoStrict::getNextRequest( } } - return pair(command, payload); + return std::pair(command, payload); } else { // The next request in the FIFO is NOT for the bank passed as parameter. @@ -116,18 +116,18 @@ std::pair FifoStrict::getNextRequest( // the next command for this request is read or write // NOP will be returned and no operation will be // performed. - return pair(Command::NOP, NULL); + return std::pair(Command::NOP, NULL); } else { // Commands other than read and write are issued normally. - return pair(command, payload); + return std::pair(command, payload); } } } } } - return pair(Command::NOP, NULL); + return std::pair(Command::NOP, NULL); } gp *FifoStrict::getPendingRequest(Bank /*bank*/) diff --git a/DRAMSys/library/src/controller/scheduler/FifoStrict.h b/DRAMSys/library/src/controller/scheduler/FifoStrict.h index acd22086..4adf3990 100644 --- a/DRAMSys/library/src/controller/scheduler/FifoStrict.h +++ b/DRAMSys/library/src/controller/scheduler/FifoStrict.h @@ -40,7 +40,7 @@ #define FIFOSTRICT_H #include -#include +//#include #include #include "../core/ControllerCore.h" diff --git a/DRAMSys/library/src/simulation/Arbiter.cpp b/DRAMSys/library/src/simulation/Arbiter.cpp index f417eb1e..0459445d 100644 --- a/DRAMSys/library/src/simulation/Arbiter.cpp +++ b/DRAMSys/library/src/simulation/Arbiter.cpp @@ -40,7 +40,7 @@ using namespace std; using namespace tlm; -Arbiter::Arbiter(sc_module_name) : payloadEventQueue(this, &Arbiter::peqCallback) +Arbiter::Arbiter(sc_module_name /*name*/) : payloadEventQueue(this, &Arbiter::peqCallback) { // The arbiter communicates with one or more memory unity through one or more sockets (one or more memory channels). // Each of the arbiter's initiator sockets is bound to a memory controller's target socket. @@ -66,6 +66,7 @@ Arbiter::Arbiter(sc_module_name) : payloadEventQueue(this, &Arbiter::peqCallback tlm_sync_enum Arbiter::nb_transport_fw(int id, tlm_generic_payload &payload, tlm_phase &phase, sc_time &fwDelay) { + // TODO: clkAlign necessary? sc_time notDelay = clkAlign(sc_time_stamp() + fwDelay) - (sc_time_stamp() + fwDelay); if (phase == BEGIN_REQ) @@ -124,6 +125,7 @@ void Arbiter::peqCallback(tlm_generic_payload &payload, const tlm_phase &phase) unsigned int channelId = DramExtension::getExtension(payload).getChannel().ID(); // Check the valid range of initiatorSocket ID and channel Id + // TODO: initiatorSocket ID not checked assert(channelId < Configuration::getInstance().NumberOfMemChannels); // Phases initiated by the intiator side from arbiter's point of view (devices performing memory requests to the arbiter) diff --git a/DRAMSys/library/src/simulation/DRAMSys.cpp b/DRAMSys/library/src/simulation/DRAMSys.cpp index 5b48fc92..30b2393e 100644 --- a/DRAMSys/library/src/simulation/DRAMSys.cpp +++ b/DRAMSys/library/src/simulation/DRAMSys.cpp @@ -175,7 +175,7 @@ void DRAMSys::logo() void DRAMSys::setupDebugManager(const string &traceName) { auto &dbg = DebugManager::getInstance(); - dbg.writeToConsole = true; + dbg.writeToConsole = false; dbg.writeToFile = true; if (dbg.writeToFile) dbg.openDebugFile(traceName + ".txt"); diff --git a/coding-style.md b/coding-style.md index 7647bd95..80291bc1 100644 --- a/coding-style.md +++ b/coding-style.md @@ -148,7 +148,7 @@ There is a plugin for VIM. More information can be found in ## Applying the Coding Style The script [make_pretty.sh](./utils/make_pretty.sh) applies the coding style -to the project excluding thrid party code. +to the project excluding third party code. ## References From 4454b82363695d235b5d625bd9808160fe394e7d Mon Sep 17 00:00:00 2001 From: Lukas Steiner Date: Mon, 10 Jun 2019 00:52:26 +0200 Subject: [PATCH 69/97] No changes, some TODOs for future work. --- DRAMSys/library/src/common/dramExtension.h | 47 +++++++------------ DRAMSys/library/src/controller/Controller.cpp | 23 ++++++++- DRAMSys/library/src/controller/Controller.h | 16 ++----- .../core/scheduling/checker/ActBChecker.h | 5 +- .../core/scheduling/checker/PreBChecker.cpp | 2 +- .../src/controller/scheduler/FifoStrict.cpp | 4 +- 6 files changed, 48 insertions(+), 49 deletions(-) diff --git a/DRAMSys/library/src/common/dramExtension.h b/DRAMSys/library/src/common/dramExtension.h index 19176cc5..c990e912 100644 --- a/DRAMSys/library/src/common/dramExtension.h +++ b/DRAMSys/library/src/common/dramExtension.h @@ -45,15 +45,13 @@ class Thread { public: - explicit Thread(unsigned int id) : - id(id) - { - } + explicit Thread(unsigned int id) : id(id) {} unsigned int ID() const { return id; } + private: unsigned int id; }; @@ -61,14 +59,13 @@ private: class Channel { public: - explicit Channel(unsigned int id) : - id(id) - { - } + explicit Channel(unsigned int id) : id(id) {} + unsigned int ID() const { return id; } + private: unsigned int id; }; @@ -76,14 +73,13 @@ private: class BankGroup { public: - explicit BankGroup(unsigned int id) : - id(id) - { - } + explicit BankGroup(unsigned int id) : id(id) {} + unsigned int ID() const { return id; } + private: unsigned int id; }; @@ -91,10 +87,8 @@ private: class Bank { public: - Bank(unsigned int id) : - id(id) - { - } + Bank(unsigned int id) : id(id) {} + unsigned int ID() const { return id; @@ -110,7 +104,6 @@ public: return std::to_string(id); } - private: unsigned int id; }; @@ -120,14 +113,9 @@ class Row public: static const Row NO_ROW; - Row() : - id(0), isNoRow(true) - { - } - explicit Row(unsigned int id) : - id(id), isNoRow(false) - { - } + Row() : id(0), isNoRow(true) {} + + explicit Row(unsigned int id) : id(id), isNoRow(false) {} unsigned int ID() const { @@ -135,6 +123,7 @@ public: } const Row operator++(); + private: unsigned int id; bool isNoRow; @@ -145,21 +134,19 @@ private: class Column { public: - explicit Column(unsigned int id) : - id(id) - { - } + explicit Column(unsigned int id) : id(id) {} unsigned int ID() const { return id; } + private: unsigned int id; }; -class DramExtension: public tlm::tlm_extension +class DramExtension : public tlm::tlm_extension { public: DramExtension(); diff --git a/DRAMSys/library/src/controller/Controller.cpp b/DRAMSys/library/src/controller/Controller.cpp index dfc021ba..844e5d09 100644 --- a/DRAMSys/library/src/controller/Controller.cpp +++ b/DRAMSys/library/src/controller/Controller.cpp @@ -39,6 +39,19 @@ #include "Controller.h" #include +Controller::Controller(sc_module_name /*name*/) : + frontendPEQ(this, &Controller::frontendPEQCallback), + dramPEQ(this, &Controller::dramPEQCallback), + controllerCorePEQ(this, &Controller::controllerCorePEQCallback), + debugManager(DebugManager::getInstance()) +{ + controllerCore = new ControllerCore("core", *this, numberOfPayloadsInSystem); + buildScheduler(); + iSocket.register_nb_transport_bw(this, &Controller::nb_transport_bw); + tSocket.register_nb_transport_fw(this, &Controller::nb_transport_fw); + tSocket.register_transport_dbg(this, &Controller::transport_dbg); +} + void Controller::buildScheduler() { string selectedScheduler = Configuration::getInstance().Scheduler; @@ -274,6 +287,7 @@ void Controller::frontendPEQCallback(tlm_generic_payload &payload, return; } payload.set_response_status(tlm::TLM_OK_RESPONSE); + // tSocket->nb_transport_bw(*backpressure, END_REQ, SC_ZERO_TIME) sendToFrontend(payload, END_REQ, SC_ZERO_TIME); scheduler->storeRequest(&payload); @@ -291,6 +305,7 @@ void Controller::frontendPEQCallback(tlm_generic_payload &payload, { printDebugMessage("##Backpressure released"); backpressure->set_response_status(tlm::TLM_OK_RESPONSE); + // tSocket->nb_transport_bw(*backpressure, END_REQ, SC_ZERO_TIME) sendToFrontend(*backpressure, END_REQ, SC_ZERO_TIME); scheduler->storeRequest(backpressure); @@ -355,6 +370,7 @@ void Controller::scheduleNextFromScheduler(Bank bank) if (controllerCore->bankIsBusy(bank)) return; + // TODO: rescheduled always true? bool rescheduled = true; pair nextRequest = scheduler->getNextRequest(bank); @@ -363,8 +379,8 @@ void Controller::scheduleNextFromScheduler(Bank bank) } else { - // TODO: getPendingRequest is only used by SMS scheduler gp *pendingRequest = scheduler->getPendingRequest(bank); + // TODO: if path (pendingRequest != NULL) is only used by SMS scheduler if (pendingRequest != NULL) { rescheduled = true; @@ -373,8 +389,10 @@ void Controller::scheduleNextFromScheduler(Bank bank) } } + // TODO: only used with FifoStrict scheduler queue blocked; - while (!blockedRequests.empty()) { + while (!blockedRequests.empty()) + { bank = blockedRequests.front(); blockedRequests.pop(); @@ -387,6 +405,7 @@ void Controller::scheduleNextFromScheduler(Bank bank) if (pendingRequest != NULL) { //Pending request if (!rescheduled) { + // TODO: never reached, rescheduled is always true rescheduled = true; frontendPEQ.notify(*(pendingRequest), PendingRequest, Configuration::getInstance().memSpec.clk); diff --git a/DRAMSys/library/src/controller/Controller.h b/DRAMSys/library/src/controller/Controller.h index 7e524a51..97ec9e73 100644 --- a/DRAMSys/library/src/controller/Controller.h +++ b/DRAMSys/library/src/controller/Controller.h @@ -81,18 +81,7 @@ DECLARE_EXTENDED_PHASE(PendingRequest); class Controller : public sc_module, public IController { public: - Controller(sc_module_name /*name*/) : - frontendPEQ(this, &Controller::frontendPEQCallback), - dramPEQ(this, &Controller::dramPEQCallback), - controllerCorePEQ(this, &Controller::controllerCorePEQCallback), - debugManager(DebugManager::getInstance()) - { - controllerCore = new ControllerCore("core", *this, numberOfPayloadsInSystem); - buildScheduler(); - iSocket.register_nb_transport_bw(this, &Controller::nb_transport_bw); - tSocket.register_nb_transport_fw(this, &Controller::nb_transport_fw); - tSocket.register_transport_dbg(this, &Controller::transport_dbg); - } + Controller(sc_module_name); virtual ~Controller() { @@ -112,8 +101,9 @@ public: virtual void send(Trigger trigger, sc_time time, tlm_generic_payload &payload) override; - tlm_utils::simple_initiator_socket iSocket; tlm_utils::simple_target_socket tSocket; + tlm_utils::simple_initiator_socket iSocket; + unsigned int getTotalNumberOfPayloadsInSystem(); void scheduleNextFromScheduler(Bank bank) override; diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/ActBChecker.h b/DRAMSys/library/src/controller/core/scheduling/checker/ActBChecker.h index 023db94f..0c83d71d 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/ActBChecker.h +++ b/DRAMSys/library/src/controller/core/scheduling/checker/ActBChecker.h @@ -33,11 +33,13 @@ */ #ifndef ACTB_CHECKER_H_ #define ACTB_CHECKER_H_ + #include #include "ICommandChecker.h" #include "../../configuration/Configuration.h" #include "../../../ControllerState.h" -class ActBChecker: public ICommandChecker + +class ActBChecker : public ICommandChecker { public: ActBChecker(const Configuration &config, @@ -53,4 +55,5 @@ private: bool satsfies_activateToActivate_differentBank(ScheduledCommand &command) const; bool satisfies_nActivateWindow(ScheduledCommand &command) const; }; + #endif /* ACTB_CHECKER_H_ */ diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/PreBChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/PreBChecker.cpp index a8376a28..97c8a103 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/PreBChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/PreBChecker.cpp @@ -34,7 +34,7 @@ #include "PreBChecker.h" #include "../../TimingCalculation.h" -void PreBChecker::delayToSatisfyConstraints(ScheduledCommand &cmd)const +void PreBChecker::delayToSatisfyConstraints(ScheduledCommand &cmd) const { sc_assert(cmd.getCommand() == Command::PreB); ScheduledCommand lastCmd = state.getLastScheduledCommand(cmd.getBank()); diff --git a/DRAMSys/library/src/controller/scheduler/FifoStrict.cpp b/DRAMSys/library/src/controller/scheduler/FifoStrict.cpp index 3f36dd9e..00701ce0 100644 --- a/DRAMSys/library/src/controller/scheduler/FifoStrict.cpp +++ b/DRAMSys/library/src/controller/scheduler/FifoStrict.cpp @@ -61,14 +61,14 @@ std::pair FifoStrict::getNextRequest( // enqueued request until the appropriate sequence of commands is // sent to the DRAM. // - // Every time getNextRequest() it is called it calls + // Every time getNextRequest() is called it calls // getNextCommand() that returns the suitable command to be sent // to the DRAM. // // getNextCommand() returns the proper command based on the // internal status of the DRAM. // - // In the worst case getNextCommand() need to be called three + // In the worst case getNextCommand() needs to be called three // times for a given element in the requests queue: first for // precharge, second for activate and finally for read or write // (accordingly the nature of the request). In contrast, for the From 02803de97cdfc3ec6c592b89b3c3dc35b93118a5 Mon Sep 17 00:00:00 2001 From: Lukas Steiner Date: Tue, 11 Jun 2019 23:10:45 +0200 Subject: [PATCH 70/97] Code refactoring. --- DRAMSys/library/src/controller/Controller.cpp | 52 ++++++++++++------- DRAMSys/library/src/controller/Controller.h | 4 +- .../src/controller/core/ControllerCore.cpp | 2 +- .../core/configuration/Configuration.h | 3 +- .../library/src/controller/scheduler/Fifo.cpp | 2 + .../library/src/controller/scheduler/Fifo.h | 4 +- .../src/controller/scheduler/IScheduler.cpp | 22 +++++--- 7 files changed, 56 insertions(+), 33 deletions(-) diff --git a/DRAMSys/library/src/controller/Controller.cpp b/DRAMSys/library/src/controller/Controller.cpp index 844e5d09..27055763 100644 --- a/DRAMSys/library/src/controller/Controller.cpp +++ b/DRAMSys/library/src/controller/Controller.cpp @@ -451,47 +451,59 @@ void Controller::dramPEQCallback(tlm_generic_payload &payload, printDebugMessage("Received " + phaseNameToString(phase) + " on bank " + to_string(bank.ID()) + " from DRAM"); - if (phase == END_RD || phase == END_WR) { - if(responseQueue.empty()) { + if (phase == END_RD || phase == END_WR) + { + if(responseQueue.empty()) sendToFrontend(payload, BEGIN_RESP, SC_ZERO_TIME); - } + responseQueue.push(&payload); - } else if (phase == END_RDA || phase == END_WRA) { - if(responseQueue.empty()) { + } + else if (phase == END_RDA || phase == END_WRA) + { + if(responseQueue.empty()) sendToFrontend(payload, BEGIN_RESP, SC_ZERO_TIME); - } + responseQueue.push(&payload); scheduleNextFromScheduler(bank); - } else if (phase == END_REFA) { + } + else if (phase == END_REFA) + { printDebugMessage("Finished auto refresh on all banks "); bool sleepy = true; - for (Bank bank : controllerCore->getBanks()) { - if (numberOfPayloadsInSystem[bank] != 0) { + for (Bank bank : controllerCore->getBanks()) + { + if (numberOfPayloadsInSystem[bank] != 0) + { sleepy = false; scheduleNextFromScheduler(bank); } } - - if (sleepy == true) { + if (sleepy == true) controllerCore->powerDownManager->sleep(0, sc_time_stamp()); - } - } else if (phase == END_REFB) { + } + else if (phase == END_REFB) + { printDebugMessage("Finished auto refresh on bank " + to_string(bank.ID())); - if (numberOfPayloadsInSystem[bank] == 0) { + if (numberOfPayloadsInSystem[bank] == 0) controllerCore->powerDownManager->sleep(bank, sc_time_stamp()); - } else { + else scheduleNextFromScheduler(bank); - } - scheduleNextFromScheduler(bank); - } else if (containsPhase(phase, {END_PREB, END_PRE, END_ACTB, END_ACT})) { + scheduleNextFromScheduler(bank); } - else if (phase == END_PRE_ALL) { + else if (containsPhase(phase, {END_PREB, END_PRE, END_ACTB, END_ACT})) + { + scheduleNextFromScheduler(bank); + } + else if (phase == END_PRE_ALL) + { // No need to trigger anything for a END_PRE_ALL. It is followed by a AUTO_REFRESH anyway (in our current // scheduler implementation) - } else { + } + else + { string str = string("DRAM PEQ in controller wrapper was triggered with unsupported phase ") + phaseNameToString(phase); diff --git a/DRAMSys/library/src/controller/Controller.h b/DRAMSys/library/src/controller/Controller.h index 97ec9e73..8df4f8b0 100644 --- a/DRAMSys/library/src/controller/Controller.h +++ b/DRAMSys/library/src/controller/Controller.h @@ -145,9 +145,9 @@ protected: //Scheduler* scheduler; IScheduler *scheduler; std::map numberOfPayloadsInSystem; - std::vector refreshCollisionRequets; + std::vector refreshCollisionRequets; tlm::tlm_generic_payload *backpressure = NULL; - std::queue responseQueue; + std::queue responseQueue; tlm_utils::peq_with_cb_and_phase frontendPEQ; tlm_utils::peq_with_cb_and_phase dramPEQ; diff --git a/DRAMSys/library/src/controller/core/ControllerCore.cpp b/DRAMSys/library/src/controller/core/ControllerCore.cpp index 63069368..ba8d1ebe 100644 --- a/DRAMSys/library/src/controller/core/ControllerCore.cpp +++ b/DRAMSys/library/src/controller/core/ControllerCore.cpp @@ -169,7 +169,7 @@ bool ControllerCore::scheduleRequest(Command command, sc_time start = clkAlign(sc_time_stamp()); state->cleanUp(start); ScheduledCommand scheduledCommand = schedule(command, start, payload); - if (config.ControllerCoreRefDisable == true) { + if (config.ControllerCoreRefDisable) { state->change(scheduledCommand); controller.send(scheduledCommand, payload); return true; diff --git a/DRAMSys/library/src/controller/core/configuration/Configuration.h b/DRAMSys/library/src/controller/core/configuration/Configuration.h index c20e35f7..37b7f4ea 100644 --- a/DRAMSys/library/src/controller/core/configuration/Configuration.h +++ b/DRAMSys/library/src/controller/core/configuration/Configuration.h @@ -54,7 +54,8 @@ enum class EPowerDownMode {NoPowerDown, Staggered, TimeoutPDN, TimeoutSREF}; enum class ECCControllerMode {Disabled, Hamming}; -struct Configuration { +struct Configuration +{ static std::string memspecUri; static std::string mcconfigUri; std::string pathToResources; diff --git a/DRAMSys/library/src/controller/scheduler/Fifo.cpp b/DRAMSys/library/src/controller/scheduler/Fifo.cpp index 305e2798..71e098b6 100644 --- a/DRAMSys/library/src/controller/scheduler/Fifo.cpp +++ b/DRAMSys/library/src/controller/scheduler/Fifo.cpp @@ -57,7 +57,9 @@ std::pair Fifo::getNextRequest(Bank bank) return std::pair(command, payload); } else + { return std::pair(Command::NOP, NULL); + } } gp *Fifo::getPendingRequest(Bank /*bank*/) diff --git a/DRAMSys/library/src/controller/scheduler/Fifo.h b/DRAMSys/library/src/controller/scheduler/Fifo.h index dfb5820c..14a9f34c 100644 --- a/DRAMSys/library/src/controller/scheduler/Fifo.h +++ b/DRAMSys/library/src/controller/scheduler/Fifo.h @@ -52,8 +52,8 @@ public: virtual ~Fifo() {} void storeRequest(gp *payload) override; - std::pair getNextRequest( - Bank bank) override; + std::pair + getNextRequest(Bank bank) override; virtual gp *getPendingRequest(Bank bank) override; private: diff --git a/DRAMSys/library/src/controller/scheduler/IScheduler.cpp b/DRAMSys/library/src/controller/scheduler/IScheduler.cpp index 09d53b47..2a9b6eff 100644 --- a/DRAMSys/library/src/controller/scheduler/IScheduler.cpp +++ b/DRAMSys/library/src/controller/scheduler/IScheduler.cpp @@ -50,13 +50,18 @@ void IScheduler::printDebugMessage(std::string message) Command IScheduler::getNextCommand(gp &payload) { Bank bank = DramExtension::getBank(payload); - if (!controllerCore.getRowBufferStates().rowBufferIsOpen(bank)) { + if (!controllerCore.getRowBufferStates().rowBufferIsOpen(bank)) + { return Command::Activate; - } else if (controllerCore.getRowBufferStates().rowBufferIsOpen(bank) && + } + else if (controllerCore.getRowBufferStates().rowBufferIsOpen(bank) && controllerCore.getRowBufferStates().getRowInRowBuffer(bank) != - DramExtension::getRow(payload)) { + DramExtension::getRow(payload)) + { return Command::Precharge; - } else { + } + else + { return getReadWriteCommand(payload); } } @@ -68,13 +73,15 @@ Command IScheduler::getNextCommand(gp *payload) Command IScheduler::getReadWriteCommand(gp &payload) { - - if (payload.get_command() == tlm::TLM_READ_COMMAND) { + if (payload.get_command() == tlm::TLM_READ_COMMAND) + { if (Configuration::getInstance().OpenPagePolicy) return Command::Read; else return Command::ReadA; - } else { + } + else + { if (Configuration::getInstance().OpenPagePolicy) return Command::Write; else @@ -86,3 +93,4 @@ Command IScheduler::getReadWriteCommand(gp *payload) { return getReadWriteCommand(*payload); } + From e7704a74e6fa6bacb4f662953bef19572724aca6 Mon Sep 17 00:00:00 2001 From: Lukas Steiner Date: Tue, 11 Jun 2019 23:11:39 +0200 Subject: [PATCH 71/97] Code refactoring. --- DRAMSys/library/library.pro | 2 + DRAMSys/library/src/simulation/Dram.cpp | 602 ++++++++++++++++++ DRAMSys/library/src/simulation/Dram.h | 524 +-------------- .../library/src/simulation/RecordableDram.cpp | 135 ++++ .../library/src/simulation/RecordableDram.h | 102 +-- 5 files changed, 772 insertions(+), 593 deletions(-) create mode 100644 DRAMSys/library/src/simulation/Dram.cpp create mode 100644 DRAMSys/library/src/simulation/RecordableDram.cpp diff --git a/DRAMSys/library/library.pro b/DRAMSys/library/library.pro index a1c1b07a..8063b653 100644 --- a/DRAMSys/library/library.pro +++ b/DRAMSys/library/library.pro @@ -144,6 +144,8 @@ SOURCES += \ src/common/AddressDecoder.cpp \ src/controller/scheduler/grp.cpp \ src/common/congenAddressDecoder.cpp \ + src/simulation/Dram.cpp \ + src/simulation/RecordableDram.cpp \ src/simulation/Arbiter.cpp HEADERS += \ diff --git a/DRAMSys/library/src/simulation/Dram.cpp b/DRAMSys/library/src/simulation/Dram.cpp new file mode 100644 index 00000000..68b3acb0 --- /dev/null +++ b/DRAMSys/library/src/simulation/Dram.cpp @@ -0,0 +1,602 @@ +/* + * Copyright (c) 2015, University of Kaiserslautern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: + * Robert Gernhardt + * Matthias Jung + * Peter Ehses + * Eder F. Zulian + * Felipe S. Prado + */ + +#include "Dram.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../common/DebugManager.h" +#include "../common/dramExtension.h" +#include "../controller/Controller.h" +#include "../controller/core/TimingCalculation.h" +#include "../controller/core/configuration/Configuration.h" +#include "../common/protocol.h" +#include "../common/Utils.h" +#include "../common/third_party/DRAMPower/src/libdrampower/LibDRAMPower.h" +#include "../error/errormodel.h" + +using namespace std; +using namespace tlm; +using namespace Data; + + +Dram::Dram(sc_module_name) : tSocket("socket") +{ + // Adjust number of bytes per burst dynamically to the selected ecc controller + bytesPerBurst = Configuration::getInstance().adjustNumBytesAfterECC( + bytesPerBurst); + dramController = NULL; + + std::uint64_t memorySize = Configuration::getInstance().getSimMemSizeInBytes(); + if (Configuration::getInstance().UseMalloc) + { + memory = (unsigned char *)malloc(memorySize); + if (!memory) + { + SC_REPORT_FATAL(this->name(), "Memory allocation failed"); + } + } + else + { + // 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); + } + + tSocket.register_nb_transport_fw(this, &Dram::nb_transport_fw); + tSocket.register_transport_dbg(this, &Dram::transport_dbg); + + if (powerAnalysis) + { + sc_time clk = Configuration::getInstance().memSpec.clk; + + MemArchitectureSpec memArchSpec; + memArchSpec.burstLength = + Configuration::getInstance().memSpec.BurstLength; + memArchSpec.dataRate = Configuration::getInstance().memSpec.DataRate; + memArchSpec.nbrOfRows = + Configuration::getInstance().memSpec.NumberOfRows; + memArchSpec.nbrOfBanks = + Configuration::getInstance().memSpec.NumberOfBanks; + memArchSpec.nbrOfColumns = + Configuration::getInstance().memSpec.NumberOfColumns; + memArchSpec.nbrOfRanks = + Configuration::getInstance().memSpec.NumberOfRanks; + memArchSpec.width = Configuration::getInstance().memSpec.bitWidth; + memArchSpec.nbrOfBankGroups = + Configuration::getInstance().memSpec.NumberOfBankGroups; + memArchSpec.twoVoltageDomains = (Configuration::getInstance().memSpec.vDD2 == 0 + ? false : true); + memArchSpec.dll = Configuration::getInstance().memSpec.DLL; + + MemTimingSpec memTimingSpec; + memTimingSpec.FAWB = Configuration::getInstance().tfawbclk; + memTimingSpec.RASB = Configuration::getInstance().trasbclk; + memTimingSpec.RCB = Configuration::getInstance().trcbclk; + memTimingSpec.RPB = Configuration::getInstance().trpbclk; + memTimingSpec.RRDB = Configuration::getInstance().trrdblclk; + memTimingSpec.RRDB_L = Configuration::getInstance().trrdblclk; + memTimingSpec.RRDB_S = Configuration::getInstance().trrdblclk; + memTimingSpec.AL = Configuration::getInstance().memSpec.tAL / clk; + memTimingSpec.CCD = Configuration::getInstance().memSpec.tCCD_S / clk; + memTimingSpec.CCD_L = Configuration::getInstance().memSpec.tCCD_L / clk; + memTimingSpec.CCD_S = Configuration::getInstance().memSpec.tCCD_S / clk; + memTimingSpec.CKE = Configuration::getInstance().memSpec.tCKE / clk; + memTimingSpec.CKESR = Configuration::getInstance().memSpec.tCKESR / clk; + memTimingSpec.clkMhz = Configuration::getInstance().memSpec.clkMHz; + // See also MemTimingSpec.cc in DRAMPower + memTimingSpec.clkPeriod = 1000.0 / Configuration::getInstance().memSpec.clkMHz; + memTimingSpec.DQSCK = Configuration::getInstance().memSpec.tDQSCK / clk; + memTimingSpec.FAW = Configuration::getInstance().memSpec.tNAW / clk; + memTimingSpec.RAS = Configuration::getInstance().memSpec.tRAS / clk; + memTimingSpec.RC = Configuration::getInstance().memSpec.tRC / clk; + memTimingSpec.RCD = Configuration::getInstance().memSpec.tRCD / clk; + memTimingSpec.REFI = Configuration::getInstance().memSpec.tREFI / clk; + auto m = Configuration::getInstance().getRefMode(); + if (m == 4) + memTimingSpec.RFC = Configuration::getInstance().memSpec.tRFC4 / clk; + else if (m == 2) + memTimingSpec.RFC = Configuration::getInstance().memSpec.tRFC2 / clk; + else + memTimingSpec.RFC = Configuration::getInstance().memSpec.tRFC / clk; + memTimingSpec.RL = Configuration::getInstance().memSpec.tRL / clk; + memTimingSpec.RP = Configuration::getInstance().memSpec.tRP / clk; + memTimingSpec.RRD = Configuration::getInstance().memSpec.tRRD_S / clk; + memTimingSpec.RRD_L = Configuration::getInstance().memSpec.tRRD_L / clk; + memTimingSpec.RRD_S = Configuration::getInstance().memSpec.tRRD_S / clk; + memTimingSpec.RTP = Configuration::getInstance().memSpec.tRTP / clk; + memTimingSpec.TAW = Configuration::getInstance().memSpec.tNAW / clk; + memTimingSpec.WL = Configuration::getInstance().memSpec.tWL / clk; + memTimingSpec.WR = Configuration::getInstance().memSpec.tWR / clk; + memTimingSpec.WTR = Configuration::getInstance().memSpec.tWTR_S / clk; + memTimingSpec.WTR_L = Configuration::getInstance().memSpec.tWTR_L / clk; + memTimingSpec.WTR_S = Configuration::getInstance().memSpec.tWTR_S / clk; + memTimingSpec.XP = Configuration::getInstance().memSpec.tXP / clk; + memTimingSpec.XPDLL = Configuration::getInstance().memSpec.tXPDLL / clk; + memTimingSpec.XS = Configuration::getInstance().memSpec.tXSR / clk; + memTimingSpec.XSDLL = Configuration::getInstance().memSpec.tXSRDLL / clk; + + MemPowerSpec memPowerSpec; + memPowerSpec.idd0 = Configuration::getInstance().memSpec.iDD0; + memPowerSpec.idd02 = Configuration::getInstance().memSpec.iDD02; + memPowerSpec.idd2p0 = Configuration::getInstance().memSpec.iDD2P0; + memPowerSpec.idd2p02 = Configuration::getInstance().memSpec.iDD2P02; + memPowerSpec.idd2p1 = Configuration::getInstance().memSpec.iDD2P1; + memPowerSpec.idd2p12 = Configuration::getInstance().memSpec.iDD2P12; + memPowerSpec.idd2n = Configuration::getInstance().memSpec.iDD2N; + memPowerSpec.idd2n2 = Configuration::getInstance().memSpec.iDD2N2; + memPowerSpec.idd3p0 = Configuration::getInstance().memSpec.iDD3P0; + memPowerSpec.idd3p02 = Configuration::getInstance().memSpec.iDD3P02; + memPowerSpec.idd3p1 = Configuration::getInstance().memSpec.iDD3P1; + memPowerSpec.idd3p12 = Configuration::getInstance().memSpec.iDD3P12; + memPowerSpec.idd3n = Configuration::getInstance().memSpec.iDD3N; + memPowerSpec.idd3n2 = Configuration::getInstance().memSpec.iDD3N2; + memPowerSpec.idd4r = Configuration::getInstance().memSpec.iDD4R; + memPowerSpec.idd4r2 = Configuration::getInstance().memSpec.iDD4R2; + memPowerSpec.idd4w = Configuration::getInstance().memSpec.iDD4W; + memPowerSpec.idd4w2 = Configuration::getInstance().memSpec.iDD4W2; + memPowerSpec.idd5 = Configuration::getInstance().memSpec.iDD5; + memPowerSpec.idd52 = Configuration::getInstance().memSpec.iDD52; + memPowerSpec.idd6 = Configuration::getInstance().memSpec.iDD6; + memPowerSpec.idd62 = Configuration::getInstance().memSpec.iDD62; + memPowerSpec.vdd = Configuration::getInstance().memSpec.vDD; + memPowerSpec.vdd2 = Configuration::getInstance().memSpec.vDD2; + + MemorySpecification memSpec; + memSpec.id = Configuration::getInstance().memSpec.MemoryId; + memSpec.memoryType = Configuration::getInstance().memSpec.MemoryType; + memSpec.memTimingSpec = memTimingSpec; + memSpec.memPowerSpec = memPowerSpec; + memSpec.memArchSpec = memArchSpec; + + DRAMPower = new libDRAMPower(memSpec, 0); + } + + // Bandwidth Calculation: + numberOfTransactionsServed = 0; + firstAccess = SC_ZERO_TIME; + lastAccess = SC_ZERO_TIME; + + // For each bank in a channel a error Model is created: + if (StoreMode == StorageMode::ErrorModel) + { + for (unsigned i = 0; i < Configuration::getInstance().memSpec.NumberOfBanks; + i++) + { + errorModel *em; + std::string errorModelStr = "errorModel_bank" + std::to_string(i); + if (powerAnalysis) + em = new errorModel(errorModelStr.c_str(), DRAMPower); + else + em = new errorModel(errorModelStr.c_str()); + ememory.push_back(em); + } + } +} + +Dram::~Dram() +{ + if (powerAnalysis) + { + if (!Configuration::getInstance().DatabaseRecording) + DRAMPower->calcEnergy(); + + // Print the final total energy and the average power for + // the simulation: + cout << name() << string(" Total Energy: ") + << fixed << std::setprecision( 2 ) + << DRAMPower->getEnergy().total_energy + * Configuration::getInstance().NumberOfDevicesOnDIMM + << string(" pJ") + << endl; + + cout << name() << string(" Average Power: ") + << fixed << std::setprecision( 2 ) + << DRAMPower->getPower().average_power + * Configuration::getInstance().NumberOfDevicesOnDIMM + << string(" mW") << endl; + } + + // Bandwidth: + + sc_time activeTime = numberOfTransactionsServed + * Configuration::getInstance().memSpec.BurstLength + / Configuration::getInstance().memSpec.DataRate + * Configuration::getInstance().memSpec.clk; + + sc_time idleTime = dramController->getIdleTime(); + sc_time endTime = dramController->getEndTime(); + sc_time startTime = dramController->getStartTime(); + + double bandwidth = (activeTime / (endTime - startTime) * 100); + double bandwidth_IDLE = ((activeTime) / (endTime - startTime - idleTime) * 100); + + double maxBandwidth = ( + // clk in Mhz e.g. 800 [MHz]: + (1000000 / Configuration::getInstance().memSpec.clk.to_double()) + // DataRate e.g. 2 + * Configuration::getInstance().memSpec.DataRate + // BusWidth e.g. 8 or 64 + * Configuration::getInstance().memSpec.bitWidth + // Number of devices on a DIMM e.g. 8 + * Configuration::getInstance().NumberOfDevicesOnDIMM ) / ( 1024 ); + + cout << name() << string(" Total Time: ") + << (endTime - startTime).to_string() + << endl; + cout << name() << string(" AVG BW: ") + << std::fixed << std::setprecision(2) + << ((bandwidth / 100)*maxBandwidth) + << " Gibit/s (" << bandwidth << " %)" + << endl; + cout << name() << string(" AVG BW/IDLE: ") + << std::fixed << std::setprecision(2) + << ((bandwidth_IDLE / 100)*maxBandwidth) + << " Gibit/s (" << (bandwidth_IDLE) << " %)" + << endl; + cout << name() << string(" MAX BW: ") + << std::fixed << std::setprecision(2) + << maxBandwidth << " Gibit/s" + << endl; + // Clean up: + for (auto e : ememory) + delete e; + + if (Configuration::getInstance().UseMalloc) + free(memory); +} + +tlm_sync_enum Dram::nb_transport_fw(tlm_generic_payload &payload, + tlm_phase &phase, sc_time &delay) +{ + if (numberOfTransactionsServed == 0) + firstAccess = sc_time_stamp(); + else + lastAccess = sc_time_stamp(); + + unsigned int bank = DramExtension::getExtension(payload).getBank().ID(); + + // This is only needed for power simulation: + unsigned long long cycle = 0; + if (powerAnalysis) + { + cycle = sc_time_stamp().value() / + Configuration::getInstance().memSpec.clk.value(); + } + + if (phase == BEGIN_PREB) + { + if (powerAnalysis) + DRAMPower->doCommand(MemCommand::PREB, bank, cycle); + + sendToController(payload, END_PREB, delay + getExecutionTime(Command::PreB, + payload)); + } + else if (phase == BEGIN_PRE) + { + if (powerAnalysis) + DRAMPower->doCommand(MemCommand::PRE, bank, cycle); + + sendToController(payload, END_PRE, delay + getExecutionTime(Command::Precharge, + payload)); + } + else if (phase == BEGIN_PRE_ALL) + { + if (powerAnalysis) + DRAMPower->doCommand(MemCommand::PREA, bank, cycle); + + sendToController(payload, END_PRE_ALL, + delay + getExecutionTime(Command::PrechargeAll, payload)); + } + else if (phase == BEGIN_ACTB) + { + if (powerAnalysis) + DRAMPower->doCommand(MemCommand::ACTB, bank, cycle); + + sendToController(payload, END_ACTB, delay + getExecutionTime(Command::ActB, + payload)); + unsigned int row = DramExtension::getExtension(payload).getRow().ID(); + if (StoreMode == StorageMode::ErrorModel) + ememory[bank]->activate(row); + } + else if (phase == BEGIN_ACT) + { + if (powerAnalysis) + DRAMPower->doCommand(MemCommand::ACT, bank, cycle); + + sendToController(payload, END_ACT, delay + getExecutionTime(Command::Activate, + payload)); + unsigned int row = DramExtension::getExtension(payload).getRow().ID(); + + if (StoreMode == StorageMode::ErrorModel) + ememory[bank]->activate(row); + } + else if (phase == BEGIN_WR) + { +#if !defined (DRAMSYS_PCT) && !defined (DRAMSYS_GEM5) + assert(payload.get_data_length() == bytesPerBurst); +#endif + + if (powerAnalysis) + DRAMPower->doCommand(MemCommand::WR, bank, cycle); + + numberOfTransactionsServed++; + + // save data: + if (StoreMode == StorageMode::NoStorage) // Don't store data + {} + else if (StoreMode == StorageMode::Store) // Use Storage + { + unsigned char *phyAddr = memory + payload.get_address(); + memcpy(phyAddr, payload.get_data_ptr(), payload.get_data_length()); + } + else // if (StoreMode == StorageMode::ErrorModel) // Use Storage with Error Model + { + ememory[bank]->store(payload); + } + sendToController(payload, END_WR, delay + getExecutionTime(Command::Write, + payload)); + } + else if (phase == BEGIN_RD) + { +#if !defined (DRAMSYS_PCT) && !defined (DRAMSYS_GEM5) + assert(payload.get_data_length() == bytesPerBurst); +#endif + + numberOfTransactionsServed++; + if (powerAnalysis) + DRAMPower->doCommand(MemCommand::RD, bank, cycle); + + // load data: + if (StoreMode == StorageMode::Store) // use StorageMode + { + unsigned char *phyAddr = memory + payload.get_address(); + memcpy(payload.get_data_ptr(), phyAddr, payload.get_data_length()); + } + else if (StoreMode == StorageMode::ErrorModel) // use StorageMode with errormodel + { + ememory[bank]->load(payload); + } + sendToController(payload, END_RD, delay + getExecutionTime(Command::Read, + payload)); + } + else if (phase == BEGIN_WRA) + { + numberOfTransactionsServed++; + if (powerAnalysis) + DRAMPower->doCommand(MemCommand::WRA, bank, cycle); + + // save data: + if (StoreMode == StorageMode::NoStorage) // Don't store data + {} + else if (StoreMode == StorageMode::Store) // Use Storage + { + unsigned char *phyAddr = memory + payload.get_address(); + memcpy(phyAddr, payload.get_data_ptr(), payload.get_data_length()); + } + else // if (StoreMode == StorageMode::ErrorModel) // Use Storage with Error Model + { + ememory[bank]->store(payload); + } + sendToController(payload, END_WRA, delay + getExecutionTime(Command::WriteA, + payload)); + } + else if (phase == BEGIN_RDA) + { + numberOfTransactionsServed++; + if (powerAnalysis) + DRAMPower->doCommand(MemCommand::RDA, bank, cycle); + + // Load data: + if (StoreMode == StorageMode::Store) // use StorageMode + { + unsigned char *phyAddr = memory + payload.get_address(); + memcpy(payload.get_data_ptr(), phyAddr, payload.get_data_length()); + } + else if (StoreMode == StorageMode::ErrorModel) // use StorageMode with errormodel + { + ememory[bank]->load(payload); + } + sendToController(payload, END_RDA, delay + getExecutionTime(Command::ReadA, + payload)); + } + else if (phase == BEGIN_REFA) + { + if (powerAnalysis) + DRAMPower->doCommand(MemCommand::REF, bank, cycle); + + sendToController(payload, END_REFA, + delay + getExecutionTime(Command::AutoRefresh, payload)); + unsigned int row = DramExtension::getExtension(payload).getRow().ID(); + + if (StoreMode == StorageMode::ErrorModel) + ememory[bank]->refresh(row); + } + else if (phase == BEGIN_REFB) + { + if (powerAnalysis) + DRAMPower->doCommand(MemCommand::REFB, bank, cycle); + + sendToController(payload, END_REFB, + delay + getExecutionTime(Command::AutoRefresh, payload)); + } + // Powerdown phases have to be started and ended by the controller, because they do not have a fixed length + else if (phase == BEGIN_PDNA) + { + if (powerAnalysis) + DRAMPower->doCommand(MemCommand::PDN_S_ACT, bank, cycle); + } + else if (phase == END_PDNA) + { + if (powerAnalysis) + DRAMPower->doCommand(MemCommand::PUP_ACT, bank, cycle); + } + else if (phase == BEGIN_PDNAB) + { + if (powerAnalysis) + SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); + } + else if (phase == END_PDNAB) + { + if (powerAnalysis) + SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); + } + else if (phase == BEGIN_PDNP) + { + if (powerAnalysis) + DRAMPower->doCommand(MemCommand::PDN_S_PRE, bank, cycle); + } + else if (phase == END_PDNP) + { + if (powerAnalysis) + DRAMPower->doCommand(MemCommand::PUP_PRE, bank, cycle); + } + else if (phase == BEGIN_PDNPB) + { + if (powerAnalysis) + SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); + } + else if (phase == END_PDNPB) + { + if (powerAnalysis) + SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); + } + else if (phase == BEGIN_SREF) + { + if (powerAnalysis) + DRAMPower->doCommand(MemCommand::SREN, bank, cycle); + } + else if (phase == END_SREF) + { + if (powerAnalysis) + DRAMPower->doCommand(MemCommand::SREX, bank, cycle); + } + else if (phase == BEGIN_SREFB) + { + if (powerAnalysis) + SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); + } + else if (phase == END_SREFB) + { + if (powerAnalysis) + SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); + } + else + { + if (powerAnalysis) + SC_REPORT_FATAL("DRAM", "DRAM PEQ was called with unknown phase"); + } + + return tlm::TLM_ACCEPTED; +} + +unsigned int Dram::transport_dbg(tlm_generic_payload &trans) +{ + printDebugMessage("transport_dgb"); + + // TODO: This part is not tested yet, neither with traceplayers nor with GEM5 coupling + if (StoreMode == StorageMode::NoStorage) + { + SC_REPORT_FATAL("DRAM", + "Debug Transport is used in combination with NoStorage"); + } + else + { + tlm_command cmd = trans.get_command(); + //sc_dt::uint64 adr = trans.get_address(); // TODO: - offset; + unsigned char *ptr = trans.get_data_ptr(); + unsigned int len = trans.get_data_length(); + //unsigned int bank = DramExtension::getExtension(trans).getBank().ID(); + + //cout << "cmd " << (cmd ? "write" : "read") << " adr " << hex << adr << " len " << len << endl; + + if (cmd == TLM_READ_COMMAND) + { + if (StoreMode == StorageMode::Store) + { // Use Storage + unsigned char *phyAddr = memory + trans.get_address(); + memcpy(ptr, phyAddr, trans.get_data_length()); + } + else + { + //ememory[bank]->load(trans); + SC_REPORT_FATAL("DRAM", "Debug transport not supported with error model yet."); + } + } + else if (cmd == TLM_WRITE_COMMAND) + { + if (StoreMode == StorageMode::Store) + { // Use Storage + unsigned char *phyAddr = memory + trans.get_address(); + memcpy(phyAddr, ptr, trans.get_data_length()); + } + else + { + //ememory[bank]->store(trans); + SC_REPORT_FATAL("DRAM", "Debug transport not supported with error model yet."); + } + } + return len; + } + return 0; +} + +void Dram::sendToController(tlm_generic_payload &payload, const tlm_phase &phase, + const sc_time &delay) +{ + tlm_phase TPhase = phase; + sc_time TDelay = delay; + tSocket->nb_transport_bw(payload, TPhase, TDelay); +} + +void Dram::printDebugMessage(string message) +{ + DebugManager::getInstance().printDebugMessage(name(), message); +} + +void Dram::setDramController(Controller *contr) +{ + dramController = contr; +} diff --git a/DRAMSys/library/src/simulation/Dram.h b/DRAMSys/library/src/simulation/Dram.h index 7c383498..20817be9 100644 --- a/DRAMSys/library/src/simulation/Dram.h +++ b/DRAMSys/library/src/simulation/Dram.h @@ -40,39 +40,24 @@ #ifndef DRAM_H_ #define DRAM_H_ -#include #include #include -#include #include -#include -#include -#include -#include -#include -#include "../common/DebugManager.h" -#include "../common/dramExtension.h" #include "../controller/Controller.h" -#include "../controller/core/TimingCalculation.h" #include "../controller/core/configuration/Configuration.h" -#include "../common/protocol.h" -#include "../common/Utils.h" -#include "../common/third_party/DRAMPower/src/libdrampower/LibDRAMPower.h" #include "../error/errormodel.h" using namespace std; using namespace tlm; using namespace Data; -struct Dram : sc_module { +class Dram : public sc_module +{ +private: unsigned int bytesPerBurst = Configuration::getInstance().getBytesPerBurst(); - // TLM Related: - tlm_utils::simple_target_socket tSocket; - // Power Model related bool powerAnalysis = Configuration::getInstance().PowerAnalysis; - libDRAMPower *DRAMPower; // Bandwidth realted: unsigned long long int numberOfTransactionsServed; @@ -88,499 +73,28 @@ struct Dram : sc_module { Controller *dramController; - SC_CTOR(Dram) : tSocket("socket") - { - // Adjust number of bytes per burst dynamically to the selected ecc controller - bytesPerBurst = Configuration::getInstance().adjustNumBytesAfterECC( - bytesPerBurst); - dramController = NULL; +protected: + libDRAMPower *DRAMPower; - std::uint64_t memorySize = Configuration::getInstance().getSimMemSizeInBytes(); - if (Configuration::getInstance().UseMalloc) { - memory = (unsigned char *)malloc(memorySize); - if (!memory) { - SC_REPORT_FATAL(this->name(), "Memory allocation failed"); - } - } else { - // 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); - } + virtual tlm_sync_enum nb_transport_fw(tlm_generic_payload &payload, + tlm_phase &phase, sc_time &delay); - tSocket.register_nb_transport_fw(this, &Dram::nb_transport_fw); - tSocket.register_transport_dbg(this, &Dram::transport_dbg); - - if (powerAnalysis == true) { - sc_time clk = Configuration::getInstance().memSpec.clk; - - MemArchitectureSpec memArchSpec; - memArchSpec.burstLength = - Configuration::getInstance().memSpec.BurstLength; - memArchSpec.dataRate = Configuration::getInstance().memSpec.DataRate; - memArchSpec.nbrOfRows = - Configuration::getInstance().memSpec.NumberOfRows; - memArchSpec.nbrOfBanks = - Configuration::getInstance().memSpec.NumberOfBanks; - memArchSpec.nbrOfColumns = - Configuration::getInstance().memSpec.NumberOfColumns; - memArchSpec.nbrOfRanks = - Configuration::getInstance().memSpec.NumberOfRanks; - memArchSpec.width = Configuration::getInstance().memSpec.bitWidth; - memArchSpec.nbrOfBankGroups = - Configuration::getInstance().memSpec.NumberOfBankGroups; - memArchSpec.twoVoltageDomains = (Configuration::getInstance().memSpec.vDD2 == 0 - ? false : true); - memArchSpec.dll = Configuration::getInstance().memSpec.DLL; - - MemTimingSpec memTimingSpec; - memTimingSpec.FAWB = Configuration::getInstance().tfawbclk; - memTimingSpec.RASB = Configuration::getInstance().trasbclk; - memTimingSpec.RCB = Configuration::getInstance().trcbclk; - memTimingSpec.RPB = Configuration::getInstance().trpbclk; - memTimingSpec.RRDB = Configuration::getInstance().trrdblclk; - memTimingSpec.RRDB_L = Configuration::getInstance().trrdblclk; - memTimingSpec.RRDB_S = Configuration::getInstance().trrdblclk; - memTimingSpec.AL = Configuration::getInstance().memSpec.tAL / clk; - memTimingSpec.CCD = Configuration::getInstance().memSpec.tCCD_S / clk; - memTimingSpec.CCD_L = Configuration::getInstance().memSpec.tCCD_L / clk; - memTimingSpec.CCD_S = Configuration::getInstance().memSpec.tCCD_S / clk; - memTimingSpec.CKE = Configuration::getInstance().memSpec.tCKE / clk; - memTimingSpec.CKESR = Configuration::getInstance().memSpec.tCKESR / clk; - memTimingSpec.clkMhz = Configuration::getInstance().memSpec.clkMHz; - // See also MemTimingSpec.cc in DRAMPower - memTimingSpec.clkPeriod = 1000.0 / Configuration::getInstance().memSpec.clkMHz; - memTimingSpec.DQSCK = Configuration::getInstance().memSpec.tDQSCK / clk; - memTimingSpec.FAW = Configuration::getInstance().memSpec.tNAW / clk; - memTimingSpec.RAS = Configuration::getInstance().memSpec.tRAS / clk; - memTimingSpec.RC = Configuration::getInstance().memSpec.tRC / clk; - memTimingSpec.RCD = Configuration::getInstance().memSpec.tRCD / clk; - memTimingSpec.REFI = Configuration::getInstance().memSpec.tREFI / clk; - auto m = Configuration::getInstance().getRefMode(); - if (m == 4) - memTimingSpec.RFC = Configuration::getInstance().memSpec.tRFC4 / clk; - else if (m == 2) - memTimingSpec.RFC = Configuration::getInstance().memSpec.tRFC2 / clk; - else - memTimingSpec.RFC = Configuration::getInstance().memSpec.tRFC / clk; - memTimingSpec.RL = Configuration::getInstance().memSpec.tRL / clk; - memTimingSpec.RP = Configuration::getInstance().memSpec.tRP / clk; - memTimingSpec.RRD = Configuration::getInstance().memSpec.tRRD_S / clk; - memTimingSpec.RRD_L = Configuration::getInstance().memSpec.tRRD_L / clk; - memTimingSpec.RRD_S = Configuration::getInstance().memSpec.tRRD_S / clk; - memTimingSpec.RTP = Configuration::getInstance().memSpec.tRTP / clk; - memTimingSpec.TAW = Configuration::getInstance().memSpec.tNAW / clk; - memTimingSpec.WL = Configuration::getInstance().memSpec.tWL / clk; - memTimingSpec.WR = Configuration::getInstance().memSpec.tWR / clk; - memTimingSpec.WTR = Configuration::getInstance().memSpec.tWTR_S / clk; - memTimingSpec.WTR_L = Configuration::getInstance().memSpec.tWTR_L / clk; - memTimingSpec.WTR_S = Configuration::getInstance().memSpec.tWTR_S / clk; - memTimingSpec.XP = Configuration::getInstance().memSpec.tXP / clk; - memTimingSpec.XPDLL = Configuration::getInstance().memSpec.tXPDLL / clk; - memTimingSpec.XS = Configuration::getInstance().memSpec.tXSR / clk; - memTimingSpec.XSDLL = Configuration::getInstance().memSpec.tXSRDLL / clk; - - MemPowerSpec memPowerSpec; - memPowerSpec.idd0 = Configuration::getInstance().memSpec.iDD0; - memPowerSpec.idd02 = Configuration::getInstance().memSpec.iDD02; - memPowerSpec.idd2p0 = Configuration::getInstance().memSpec.iDD2P0; - memPowerSpec.idd2p02 = Configuration::getInstance().memSpec.iDD2P02; - memPowerSpec.idd2p1 = Configuration::getInstance().memSpec.iDD2P1; - memPowerSpec.idd2p12 = Configuration::getInstance().memSpec.iDD2P12; - memPowerSpec.idd2n = Configuration::getInstance().memSpec.iDD2N; - memPowerSpec.idd2n2 = Configuration::getInstance().memSpec.iDD2N2; - memPowerSpec.idd3p0 = Configuration::getInstance().memSpec.iDD3P0; - memPowerSpec.idd3p02 = Configuration::getInstance().memSpec.iDD3P02; - memPowerSpec.idd3p1 = Configuration::getInstance().memSpec.iDD3P1; - memPowerSpec.idd3p12 = Configuration::getInstance().memSpec.iDD3P12; - memPowerSpec.idd3n = Configuration::getInstance().memSpec.iDD3N; - memPowerSpec.idd3n2 = Configuration::getInstance().memSpec.iDD3N2; - memPowerSpec.idd4r = Configuration::getInstance().memSpec.iDD4R; - memPowerSpec.idd4r2 = Configuration::getInstance().memSpec.iDD4R2; - memPowerSpec.idd4w = Configuration::getInstance().memSpec.iDD4W; - memPowerSpec.idd4w2 = Configuration::getInstance().memSpec.iDD4W2; - memPowerSpec.idd5 = Configuration::getInstance().memSpec.iDD5; - memPowerSpec.idd52 = Configuration::getInstance().memSpec.iDD52; - memPowerSpec.idd6 = Configuration::getInstance().memSpec.iDD6; - memPowerSpec.idd62 = Configuration::getInstance().memSpec.iDD62; - memPowerSpec.vdd = Configuration::getInstance().memSpec.vDD; - memPowerSpec.vdd2 = Configuration::getInstance().memSpec.vDD2; - - MemorySpecification memSpec; - memSpec.id = Configuration::getInstance().memSpec.MemoryId; - memSpec.memoryType = Configuration::getInstance().memSpec.MemoryType; - memSpec.memTimingSpec = memTimingSpec; - memSpec.memPowerSpec = memPowerSpec; - memSpec.memArchSpec = memArchSpec; - - DRAMPower = new libDRAMPower( memSpec, 0 ); - } - - // Bandwidth Calculation: - numberOfTransactionsServed = 0; - firstAccess = SC_ZERO_TIME; - lastAccess = SC_ZERO_TIME; - - // For each bank in a channel a error Model is created: - if (StoreMode == StorageMode::ErrorModel) { - for (unsigned i = 0; i < Configuration::getInstance().memSpec.NumberOfBanks; - i++) { - errorModel *em; - std::string errorModelStr = "errorModel_bank" + std::to_string(i); - if (powerAnalysis == true) { - em = new errorModel(errorModelStr.c_str(), DRAMPower); - } else { - em = new errorModel(errorModelStr.c_str()); - } - ememory.push_back(em); - } - } - } - - virtual void end_of_simulation() - { - } - - ~Dram() - { - if (powerAnalysis == true) { - if (!Configuration::getInstance().DatabaseRecording) - DRAMPower->calcEnergy(); - - // Print the final total energy and the average power for - // the simulation: - cout << name() << string(" Total Energy: ") - << fixed << std::setprecision( 2 ) - << DRAMPower->getEnergy().total_energy - * Configuration::getInstance().NumberOfDevicesOnDIMM - << string(" pJ") - << endl; - - cout << name() << string(" Average Power: ") - << fixed << std::setprecision( 2 ) - << DRAMPower->getPower().average_power - * Configuration::getInstance().NumberOfDevicesOnDIMM - << string(" mW") << endl; - } - - // Bandwidth: - - sc_time activeTime = numberOfTransactionsServed - * Configuration::getInstance().memSpec.BurstLength - / Configuration::getInstance().memSpec.DataRate - * Configuration::getInstance().memSpec.clk; - - sc_time idleTime = dramController->getIdleTime(); - sc_time endTime = dramController->getEndTime(); - sc_time startTime = dramController->getStartTime(); - - double bandwidth = (activeTime / (endTime - startTime) * 100); - double bandwidth_IDLE = ((activeTime) / (endTime - startTime - idleTime) * 100); - - double maxBandwidth = ( - // clk in Mhz e.g. 800 [MHz]: - (1000000 / Configuration::getInstance().memSpec.clk.to_double()) - // DataRate e.g. 2 - * Configuration::getInstance().memSpec.DataRate - // BusWidth e.g. 8 or 64 - * Configuration::getInstance().memSpec.bitWidth - // Number of devices on a DIMM e.g. 8 - * Configuration::getInstance().NumberOfDevicesOnDIMM ) / ( 1024 ); - - cout << name() << string(" Total Time: ") - << (endTime - startTime).to_string() - << endl; - cout << name() << string(" AVG BW: ") - << std::fixed << std::setprecision(2) - << ((bandwidth / 100)*maxBandwidth) - << " Gibit/s (" << bandwidth << " %)" - << endl; - cout << name() << string(" AVG BW/IDLE: ") - << std::fixed << std::setprecision(2) - << ((bandwidth_IDLE / 100)*maxBandwidth) - << " Gibit/s (" << (bandwidth_IDLE) << " %)" - << endl; - cout << name() << string(" MAX BW: ") - << std::fixed << std::setprecision(2) - << maxBandwidth << " Gibit/s" - << endl; - // Clean up: - for (auto e : ememory) { - delete e; - } - - if (Configuration::getInstance().UseMalloc) { - free(memory); - } - } - - virtual tlm::tlm_sync_enum nb_transport_fw(tlm::tlm_generic_payload &payload, - tlm::tlm_phase &phase, sc_time &delay) - { - if (numberOfTransactionsServed == 0) { - firstAccess = sc_time_stamp(); - } else { - lastAccess = sc_time_stamp(); - } - - unsigned int bank = DramExtension::getExtension(payload).getBank().ID(); - - // This is only needed for power simulation: - unsigned long long cycle = 0; - if (powerAnalysis == true) { - cycle = sc_time_stamp().value() / - Configuration::getInstance().memSpec.clk.value(); - } - if (phase == BEGIN_PREB) { - if (powerAnalysis == true) { - DRAMPower->doCommand(MemCommand::PREB, bank, cycle); - } - sendToController(payload, END_PREB, delay + getExecutionTime(Command::PreB, - payload)); - } else if (phase == BEGIN_PRE) { - if (powerAnalysis == true) { - DRAMPower->doCommand(MemCommand::PRE, bank, cycle); - } - sendToController(payload, END_PRE, delay + getExecutionTime(Command::Precharge, - payload)); - } else if (phase == BEGIN_PRE_ALL) { - if (powerAnalysis == true) { - DRAMPower->doCommand(MemCommand::PREA, bank, cycle); - } - sendToController(payload, END_PRE_ALL, - delay + getExecutionTime(Command::PrechargeAll, payload)); - } else if (phase == BEGIN_ACTB) { - if (powerAnalysis == true) { - DRAMPower->doCommand(MemCommand::ACTB, bank, cycle); - } - sendToController(payload, END_ACTB, delay + getExecutionTime(Command::ActB, - payload)); - unsigned int row = DramExtension::getExtension(payload).getRow().ID(); - if (StoreMode == StorageMode::ErrorModel) { - ememory[bank]->activate(row); - } - } else if (phase == BEGIN_ACT) { - if (powerAnalysis == true) { - DRAMPower->doCommand(MemCommand::ACT, bank, cycle); - } - sendToController(payload, END_ACT, delay + getExecutionTime(Command::Activate, - payload)); - unsigned int row = DramExtension::getExtension(payload).getRow().ID(); - - if (StoreMode == StorageMode::ErrorModel) { - ememory[bank]->activate(row); - } - } else if (phase == BEGIN_WR) { -#if !defined (DRAMSYS_PCT) && !defined (DRAMSYS_GEM5) - assert(payload.get_data_length() == bytesPerBurst); -#endif - - if (powerAnalysis == true) { - DRAMPower->doCommand(MemCommand::WR, bank, cycle); - } - numberOfTransactionsServed++; - - //save data: - if (StoreMode == StorageMode::NoStorage) { - // Don't store data - } else if (StoreMode == StorageMode::Store) { // Use Storage - unsigned char *phyAddr = memory + payload.get_address(); - memcpy(phyAddr, payload.get_data_ptr(), payload.get_data_length()); - } else { // == 2 Use Storage with Error Model - ememory[bank]->store(payload); - } - sendToController(payload, END_WR, delay + getExecutionTime(Command::Write, - payload)); - } else if (phase == BEGIN_RD) { -#if !defined (DRAMSYS_PCT) && !defined (DRAMSYS_GEM5) - assert(payload.get_data_length() == bytesPerBurst); -#endif - - numberOfTransactionsServed++; - if (powerAnalysis == true) { - DRAMPower->doCommand(MemCommand::RD, bank, cycle); - } - - // Load data: - if (StoreMode == StorageMode::Store) { //use StorageMode - unsigned char *phyAddr = memory + payload.get_address(); - memcpy(payload.get_data_ptr(), phyAddr, payload.get_data_length()); - } else if (StoreMode == - StorageMode::ErrorModel) { // use StorageMode with errormodel - ememory[bank]->load(payload); - } - - sendToController(payload, END_RD, delay + getExecutionTime(Command::Read, - payload)); - } else if (phase == BEGIN_WRA) { - numberOfTransactionsServed++; - if (powerAnalysis == true) { - DRAMPower->doCommand(MemCommand::WRA, bank, cycle); - } - - //save data: - if (StoreMode == StorageMode::NoStorage) { - // Don't store data - } else if (StoreMode == StorageMode::Store) { // Use Storage - unsigned char *phyAddr = memory + payload.get_address(); - memcpy(phyAddr, payload.get_data_ptr(), payload.get_data_length()); - } else { // == 2 Use Storage with Error Model - ememory[bank]->store(payload); - } - sendToController(payload, END_WRA, delay + getExecutionTime(Command::WriteA, - payload)); - } else if (phase == BEGIN_RDA) { - numberOfTransactionsServed++; - if (powerAnalysis == true) { - DRAMPower->doCommand(MemCommand::RDA, bank, cycle); - } - - // Load data: - if (StoreMode == StorageMode::Store) { //use StorageMode - unsigned char *phyAddr = memory + payload.get_address(); - memcpy(payload.get_data_ptr(), phyAddr, payload.get_data_length()); - } else if (StoreMode == - StorageMode::ErrorModel) { // use StorageMode with errormodel - ememory[bank]->load(payload); - } - - sendToController(payload, END_RDA, delay + getExecutionTime(Command::ReadA, - payload)); - } else if (phase == BEGIN_REFA) { - if (powerAnalysis == true) { - DRAMPower->doCommand(MemCommand::REF, bank, cycle); - } - sendToController(payload, END_REFA, - delay + getExecutionTime(Command::AutoRefresh, payload)); - unsigned int row = DramExtension::getExtension(payload).getRow().ID(); - - if (StoreMode == StorageMode::ErrorModel) { - ememory[bank]->refresh(row); - } - } - - else if (phase == BEGIN_REFB) { - if (powerAnalysis == true) { - DRAMPower->doCommand(MemCommand::REFB, bank, cycle); - } - sendToController(payload, END_REFB, - delay + getExecutionTime(Command::AutoRefresh, payload)); - } - - //Powerdown phases have to be started and ended by the controller, because they do not have a fixed length - else if (phase == BEGIN_PDNA) { - if (powerAnalysis == true) { - DRAMPower->doCommand(MemCommand::PDN_S_ACT, bank, cycle); - } - } else if (phase == END_PDNA) { - if (powerAnalysis == true) { - DRAMPower->doCommand(MemCommand::PUP_ACT, bank, cycle); - } - } else if (phase == BEGIN_PDNAB) { - if (powerAnalysis == true) { - SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); - } - } else if (phase == END_PDNAB) { - if (powerAnalysis == true) { - SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); - } - } else if (phase == BEGIN_PDNP) { - if (powerAnalysis == true) { - DRAMPower->doCommand(MemCommand::PDN_S_PRE, bank, cycle); - } - } else if (phase == END_PDNP) { - if (powerAnalysis == true) { - DRAMPower->doCommand(MemCommand::PUP_PRE, bank, cycle); - } - } else if (phase == BEGIN_PDNPB) { - if (powerAnalysis == true) { - SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); - } - } else if (phase == END_PDNPB) { - if (powerAnalysis == true) { - SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); - } - } else if (phase == BEGIN_SREF) { - if (powerAnalysis == true) { - DRAMPower->doCommand(MemCommand::SREN, bank, cycle); - } - } else if (phase == END_SREF) { - if (powerAnalysis == true) { - DRAMPower->doCommand(MemCommand::SREX, bank, cycle); - } - } else if (phase == BEGIN_SREFB) { - if (powerAnalysis == true) { - SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); - } - } else if (phase == END_SREFB) { - if (powerAnalysis == true) { - SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); - } - } else { - if (powerAnalysis == true) { - SC_REPORT_FATAL("DRAM", "DRAM PEQ was called with unknown phase"); - } - } - - return tlm::TLM_ACCEPTED; - } - - virtual unsigned int transport_dbg(tlm::tlm_generic_payload &trans) - { - printDebugMessage("transport_dgb"); - - // TODO: This part is not tested yet, neither with traceplayers neither with GEM5 coupling - if (StoreMode == StorageMode::NoStorage) { - SC_REPORT_FATAL("DRAM", - "Debug Transport is used in combination with NoStorage"); - } else { - tlm::tlm_command cmd = trans.get_command(); - //sc_dt::uint64 adr = trans.get_address(); // TODO: - offset; - unsigned char *ptr = trans.get_data_ptr(); - unsigned int len = trans.get_data_length(); - //unsigned int bank = DramExtension::getExtension(trans).getBank().ID(); - - //cout << "cmd " << (cmd ? "write" : "read") << " adr " << hex << adr << " len " << len << endl; - - if ( cmd == tlm::TLM_READ_COMMAND ) { - if (StoreMode == StorageMode::Store) { // Use Storage - unsigned char *phyAddr = memory + trans.get_address(); - memcpy(ptr, phyAddr, trans.get_data_length()); - } else { - //ememory[bank]->load(trans); - SC_REPORT_FATAL("DRAM", "Debug transport not supported with error model yet."); - } - } else if ( cmd == tlm::TLM_WRITE_COMMAND ) { - - if (StoreMode == StorageMode::Store) { // Use Storage - unsigned char *phyAddr = memory + trans.get_address(); - memcpy(phyAddr, ptr, trans.get_data_length()); - } else { - //ememory[bank]->store(trans); - SC_REPORT_FATAL("DRAM", "Debug transport not supported with error model yet."); - } - - } - return len; - } - return 0; - } + virtual unsigned int transport_dbg(tlm_generic_payload &trans); void sendToController(tlm_generic_payload &payload, const tlm_phase &phase, - const sc_time &delay) - { - tlm_phase TPhase = phase; - sc_time TDelay = delay; - tSocket->nb_transport_bw(payload, TPhase, TDelay); - } + const sc_time &delay); - void printDebugMessage(string message) - { - DebugManager::getInstance().printDebugMessage(name(), message); - } + void printDebugMessage(string message); - void setDramController(Controller *contr) - { - dramController = contr; - } +public: + tlm_utils::simple_target_socket tSocket; + + Dram(sc_module_name); + SC_HAS_PROCESS(Dram); + + ~Dram(); + + void setDramController(Controller *contr); }; #endif /* DRAM_H_ */ diff --git a/DRAMSys/library/src/simulation/RecordableDram.cpp b/DRAMSys/library/src/simulation/RecordableDram.cpp new file mode 100644 index 00000000..7ba789ef --- /dev/null +++ b/DRAMSys/library/src/simulation/RecordableDram.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2018, University of Kaiserslautern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: + * Felipe S. Prado + * Matthias Jung + */ + +#include "RecordableDram.h" + +using namespace tlm; + +RecordableDram::RecordableDram(sc_module_name name, TlmRecorder *tlmRecorder) + : Dram(name), tlmRecorder(tlmRecorder) +{ + // Create a thread that is triggered every $powerWindowSize + // to generate a Power over Time plot in the Trace analyzer: + if (Configuration::getInstance().PowerAnalysis + && Configuration::getInstance().EnableWindowing) + SC_THREAD(powerWindow); +} + +RecordableDram::~RecordableDram() +{ + if (Configuration::getInstance().PowerAnalysis) + { + // Obtain the residual energy which was not covered by + // previous windows + DRAMPower->calcEnergy(); + recordPower(); + } + tlmRecorder->closeConnection(); +} + + +tlm_sync_enum RecordableDram::nb_transport_fw(tlm_generic_payload &payload, + tlm_phase &phase, sc_time &delay) +{ + // Recording time used by the traceAnalyzer + sc_time recTime = sc_time_stamp() + delay; + + // These are terminating phases recorded by the DRAM. The execution + // time of the related command must be taken into consideration. + if (phase == END_PDNA || phase == END_PDNAB) { + recTime += getExecutionTime(Command::PDNAX, payload); + } else if (phase == END_PDNP || phase == END_PDNPB) { + recTime += getExecutionTime(Command::PDNPX, payload); + } else if (phase == END_SREF || phase == END_SREFB) { + recTime += getExecutionTime(Command::SREFX, payload); + } + + unsigned int thr = DramExtension::getExtension(payload).getThread().ID(); + unsigned int ch = DramExtension::getExtension(payload).getChannel().ID(); + unsigned int bg = DramExtension::getExtension(payload).getBankGroup().ID(); + unsigned int bank = DramExtension::getExtension(payload).getBank().ID(); + unsigned int row = DramExtension::getExtension(payload).getRow().ID(); + unsigned int col = DramExtension::getExtension(payload).getColumn().ID(); + + printDebugMessage("Recording " + phaseNameToString(phase) + " thread " + + to_string(thr) + " channel " + to_string(ch) + " bank group " + to_string( + bg) + " bank " + to_string(bank) + " row " + to_string(row) + " column " + + to_string(col) + " at " + recTime.to_string()); + + tlmRecorder->recordPhase(payload, phase, recTime); + + return Dram::nb_transport_fw(payload, phase, delay); +} + +// This Thread is only triggered when Power Simulation is enabled. +// It estimates the current average power which will be stored in the trace database for visualization purposes. +void RecordableDram::powerWindow() +{ + unsigned long long clk_cycles = 0; + + do { + // At the very beginning (zero clock cycles) the energy is 0, so we wait first + wait(powerWindowSize); + + clk_cycles = sc_time_stamp().value() / + Configuration::getInstance().memSpec.clk.value(); + + DRAMPower->calcWindowEnergy(clk_cycles); + + // During operation the energy should never be zero since the device is always consuming + assert(!is_equal(DRAMPower->getEnergy().window_energy, 0.0)); + + // Store the time (in seconds) and the current average power (in mW) into the database + recordPower(); + + // Here considering that DRAMPower provides the energy in pJ and the power in mW + printDebugMessage(string("\tWindow Energy: \t") + to_string( + DRAMPower->getEnergy().window_energy * + Configuration::getInstance().NumberOfDevicesOnDIMM) + string("\t[pJ]")); + printDebugMessage(string("\tWindow Average Power: \t") + to_string( + DRAMPower->getPower().window_average_power * + Configuration::getInstance().NumberOfDevicesOnDIMM) + string("\t[mW]")); + + } while (true); +} + +void RecordableDram::recordPower() +{ + tlmRecorder->recordPower(sc_time_stamp().to_seconds(), + DRAMPower->getPower().window_average_power + * Configuration::getInstance().NumberOfDevicesOnDIMM); +} + diff --git a/DRAMSys/library/src/simulation/RecordableDram.h b/DRAMSys/library/src/simulation/RecordableDram.h index 00a2d073..669eb3cc 100644 --- a/DRAMSys/library/src/simulation/RecordableDram.h +++ b/DRAMSys/library/src/simulation/RecordableDram.h @@ -40,66 +40,25 @@ #include "Dram.h" #include "../common/TlmRecorder.h" -struct RecordableDram : public Dram { +using namespace tlm; + +class RecordableDram : public Dram +{ +public: + RecordableDram(sc_module_name, TlmRecorder *tlmRecorder); SC_HAS_PROCESS(RecordableDram); - RecordableDram(sc_module_name name, TlmRecorder *tlmRecorder): - Dram(name), tlmRecorder(tlmRecorder) - { - // Create a thread that is triggered every $powerWindowSize - // to generate a Power over Time plot in the Trace analyzer: - if (Configuration::getInstance().PowerAnalysis - && Configuration::getInstance().EnableWindowing) - SC_THREAD(powerWindow); - } - ~RecordableDram() - { - if (Configuration::getInstance().PowerAnalysis) { - // Obtain the residual energy which was not covered by - // previous windows - DRAMPower->calcEnergy(); - recordPower(); - } - tlmRecorder->closeConnection(); - } + ~RecordableDram(); +protected: + virtual tlm_sync_enum nb_transport_fw(tlm_generic_payload &payload, + tlm_phase &phase, sc_time &delay); + +private: TlmRecorder *tlmRecorder; sc_time powerWindowSize = Configuration::getInstance().memSpec.clk * Configuration::getInstance().WindowSize; - virtual tlm::tlm_sync_enum nb_transport_fw(tlm::tlm_generic_payload &payload, - tlm::tlm_phase &phase, sc_time &delay) - { - // Recording time used by the traceAnalyzer - sc_time recTime = sc_time_stamp() + delay; - - // These are terminating phases recorded by the DRAM. The execution - // time of the related command must be taken into consideration. - if (phase == END_PDNA || phase == END_PDNAB) { - recTime += getExecutionTime(Command::PDNAX, payload); - } else if (phase == END_PDNP || phase == END_PDNPB) { - recTime += getExecutionTime(Command::PDNPX, payload); - } else if (phase == END_SREF || phase == END_SREFB) { - recTime += getExecutionTime(Command::SREFX, payload); - } - - unsigned int thr = DramExtension::getExtension(payload).getThread().ID(); - unsigned int ch = DramExtension::getExtension(payload).getChannel().ID(); - unsigned int bg = DramExtension::getExtension(payload).getBankGroup().ID(); - unsigned int bank = DramExtension::getExtension(payload).getBank().ID(); - unsigned int row = DramExtension::getExtension(payload).getRow().ID(); - unsigned int col = DramExtension::getExtension(payload).getColumn().ID(); - - printDebugMessage("Recording " + phaseNameToString(phase) + " thread " + - to_string(thr) + " channel " + to_string(ch) + " bank group " + to_string( - bg) + " bank " + to_string(bank) + " row " + to_string(row) + " column " + - to_string(col) + " at " + recTime.to_string()); - - tlmRecorder->recordPhase(payload, phase, recTime); - - return Dram::nb_transport_fw(payload, phase, delay); - } - // When working with floats, we have to decide ourselves what is an // acceptable definition for "equal". Here the number is compared with a // suitable error margin (0.00001). @@ -110,42 +69,9 @@ struct RecordableDram : public Dram { // This Thread is only triggered when Power Simulation is enabled. // It estimates the current average power which will be stored in the trace database for visualization purposes. - void powerWindow() - { - unsigned long long clk_cycles = 0; + void powerWindow(); - do { - // At the very beginning (zero clock cycles) the energy is 0, so we wait first - wait(powerWindowSize); - - clk_cycles = sc_time_stamp().value() / - Configuration::getInstance().memSpec.clk.value(); - - DRAMPower->calcWindowEnergy(clk_cycles); - - // During operation the energy should never be zero since the device is always consuming - assert(!is_equal(DRAMPower->getEnergy().window_energy, 0.0)); - - // Store the time (in seconds) and the current average power (in mW) into the database - recordPower(); - - // Here considering that DRAMPower provides the energy in pJ and the power in mW - printDebugMessage(string("\tWindow Energy: \t") + to_string( - DRAMPower->getEnergy().window_energy * - Configuration::getInstance().NumberOfDevicesOnDIMM) + string("\t[pJ]")); - printDebugMessage(string("\tWindow Average Power: \t") + to_string( - DRAMPower->getPower().window_average_power * - Configuration::getInstance().NumberOfDevicesOnDIMM) + string("\t[mW]")); - - } while (true); - } - - void recordPower() - { - tlmRecorder->recordPower(sc_time_stamp().to_seconds(), - DRAMPower->getPower().window_average_power - * Configuration::getInstance().NumberOfDevicesOnDIMM); - } + void recordPower(); }; #endif /* RECORDABLEDRAM_H_ */ From 62c5ec720ff677e6feb80292da8af4999430006b Mon Sep 17 00:00:00 2001 From: Lukas Steiner Date: Tue, 11 Jun 2019 23:14:07 +0200 Subject: [PATCH 72/97] Code refactoring. --- DRAMSys/library/src/controller/scheduler/Fifo.cpp | 2 +- DRAMSys/library/src/controller/scheduler/FifoStrict.cpp | 6 +++--- DRAMSys/library/src/controller/scheduler/Fr_Fcfs.cpp | 2 +- .../library/src/controller/scheduler/Fr_Fcfs_grouper.cpp | 4 ++-- .../src/controller/scheduler/Fr_Fcfs_read_priority.cpp | 4 ++-- DRAMSys/library/src/controller/scheduler/SMS.cpp | 2 +- DRAMSys/library/src/controller/scheduler/grp.cpp | 4 ++-- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/DRAMSys/library/src/controller/scheduler/Fifo.cpp b/DRAMSys/library/src/controller/scheduler/Fifo.cpp index 71e098b6..cc2ddb11 100644 --- a/DRAMSys/library/src/controller/scheduler/Fifo.cpp +++ b/DRAMSys/library/src/controller/scheduler/Fifo.cpp @@ -47,7 +47,7 @@ std::pair Fifo::getNextRequest(Bank bank) if (!buffer[bank].empty()) { gp *payload = buffer[bank].front(); - Command command = IScheduler::getNextCommand(*payload); + Command command = IScheduler::getNextCommand(payload); if (command == Command::Read || command == Command::ReadA || command == Command::Write || command == Command::WriteA) { diff --git a/DRAMSys/library/src/controller/scheduler/FifoStrict.cpp b/DRAMSys/library/src/controller/scheduler/FifoStrict.cpp index 00701ce0..4b890433 100644 --- a/DRAMSys/library/src/controller/scheduler/FifoStrict.cpp +++ b/DRAMSys/library/src/controller/scheduler/FifoStrict.cpp @@ -75,7 +75,7 @@ std::pair FifoStrict::getNextRequest( // case of an already open row (due to a previous request) the // command itself could be directly issued. // - Command command = IScheduler::getNextCommand(*payload); + Command command = IScheduler::getNextCommand(payload); if (commandIsIn(command, {Command::Read, Command::Write, Command::ReadA, Command::WriteA})) { buffer.pop_front(); @@ -84,7 +84,7 @@ std::pair FifoStrict::getNextRequest( if (!buffer.empty()) { tlm::tlm_generic_payload *p = buffer.front().second; - Command cmd = IScheduler::getNextCommand(*p); + Command cmd = IScheduler::getNextCommand(p); if (commandIsIn(cmd, {Command::Read, Command::Write, Command::ReadA, Command::WriteA})) { Bank b = DramExtension::getBank(p); controller.blockedRequests.push(b); @@ -110,7 +110,7 @@ std::pair FifoStrict::getNextRequest( // Reads and writes will not be issued since this // scheduler executes all read and writes in a strict // order. - Command command = getNextCommand(*payload); + Command command = getNextCommand(payload); if (commandIsIn(command, {Command::Read, Command::Write, Command::ReadA, Command::WriteA})) { // Reads and writes must be executed in order. Then if // the next command for this request is read or write diff --git a/DRAMSys/library/src/controller/scheduler/Fr_Fcfs.cpp b/DRAMSys/library/src/controller/scheduler/Fr_Fcfs.cpp index 05a4e745..7fe82b7c 100644 --- a/DRAMSys/library/src/controller/scheduler/Fr_Fcfs.cpp +++ b/DRAMSys/library/src/controller/scheduler/Fr_Fcfs.cpp @@ -81,7 +81,7 @@ std::pair FR_FCFS::getNextRequest(Bank bank) if (it != buffer[bank].end()) { gp *payload = *it; buffer[bank].erase(it); - return pair(getReadWriteCommand(*payload), payload); + return pair(getReadWriteCommand(payload), payload); } // If there is no row hit, the FR_FCFS takes always the oldest transaction diff --git a/DRAMSys/library/src/controller/scheduler/Fr_Fcfs_grouper.cpp b/DRAMSys/library/src/controller/scheduler/Fr_Fcfs_grouper.cpp index 40a8258e..9fa2030f 100644 --- a/DRAMSys/library/src/controller/scheduler/Fr_Fcfs_grouper.cpp +++ b/DRAMSys/library/src/controller/scheduler/Fr_Fcfs_grouper.cpp @@ -74,7 +74,7 @@ std::pair FR_FCFS_GRP::getNextRequest(Bank bank) if (hazardDetection(bank, it) == false) { buffer[bank].erase(it); printDebugMessage("Read Hit found"); - return pair(getReadWriteCommand(*read), + return pair(getReadWriteCommand(read), read); } else { // If there was a hazard, switch the mode and try again: @@ -112,7 +112,7 @@ std::pair FR_FCFS_GRP::getNextRequest(Bank bank) .getRowInRowBuffer(bank)) { buffer[bank].erase(it); printDebugMessage("Write Hit found"); - return pair(getReadWriteCommand(*write), + return pair(getReadWriteCommand(write), write); } } diff --git a/DRAMSys/library/src/controller/scheduler/Fr_Fcfs_read_priority.cpp b/DRAMSys/library/src/controller/scheduler/Fr_Fcfs_read_priority.cpp index 57c2f60f..117583c6 100644 --- a/DRAMSys/library/src/controller/scheduler/Fr_Fcfs_read_priority.cpp +++ b/DRAMSys/library/src/controller/scheduler/Fr_Fcfs_read_priority.cpp @@ -62,7 +62,7 @@ std::pair FR_FCFS_RP::getNextRequest(Bank bank) if (hazardDetection(bank, it) == false) { buffer[bank].erase(it); printDebugMessage("Read Hit found"); - return pair(getReadWriteCommand(*read), read); + return pair(getReadWriteCommand(read), read); } } } @@ -78,7 +78,7 @@ std::pair FR_FCFS_RP::getNextRequest(Bank bank) == controllerCore.getRowBufferStates().getRowInRowBuffer(bank)) { buffer[bank].erase(it); printDebugMessage("Write Hit found"); - return pair(getReadWriteCommand(*write), write); + return pair(getReadWriteCommand(write), write); } } } diff --git a/DRAMSys/library/src/controller/scheduler/SMS.cpp b/DRAMSys/library/src/controller/scheduler/SMS.cpp index 0f407775..42530571 100644 --- a/DRAMSys/library/src/controller/scheduler/SMS.cpp +++ b/DRAMSys/library/src/controller/scheduler/SMS.cpp @@ -30,7 +30,7 @@ std::pair SMS::getNextRequest(Bank bank) return pair(Command::NOP, NULL); } else { gp *payload = bankBuffers[bank].front(); - Command command = IScheduler::getNextCommand(*payload); + Command command = IScheduler::getNextCommand(payload); if (command == Command::Read || command == Command::ReadA || command == Command::Write || command == Command::WriteA) { diff --git a/DRAMSys/library/src/controller/scheduler/grp.cpp b/DRAMSys/library/src/controller/scheduler/grp.cpp index 652405aa..afb06fac 100644 --- a/DRAMSys/library/src/controller/scheduler/grp.cpp +++ b/DRAMSys/library/src/controller/scheduler/grp.cpp @@ -74,7 +74,7 @@ std::pair GRP::getNextRequest(Bank bank) if (hazardDetection(bank, it) == false) { buffer[bank].erase(it); printDebugMessage("Read Hit found"); - return pair(getReadWriteCommand(*read), + return pair(getReadWriteCommand(read), read); } else { // If there was a hazard, switch the mode and try again: @@ -106,7 +106,7 @@ std::pair GRP::getNextRequest(Bank bank) .getRowInRowBuffer(bank)) { buffer[bank].erase(it); printDebugMessage("Write Hit found"); - return pair(getReadWriteCommand(*write), + return pair(getReadWriteCommand(write), write); } else { printDebugMessage("Write miss found"); From 5ac2701d2c809bfabe1a4123bd4e3e0eb55ea14e Mon Sep 17 00:00:00 2001 From: Lukas Steiner Date: Wed, 12 Jun 2019 00:52:28 +0200 Subject: [PATCH 73/97] Fix commit for renaming issue. --- .../scheduler/{grp.cpp => Grp_rename.cpp} | 18 +++++++++--------- .../scheduler/{grp.h => Grp_rename.h} | 19 +++++++------------ 2 files changed, 16 insertions(+), 21 deletions(-) rename DRAMSys/library/src/controller/scheduler/{grp.cpp => Grp_rename.cpp} (92%) rename DRAMSys/library/src/controller/scheduler/{grp.h => Grp_rename.h} (89%) diff --git a/DRAMSys/library/src/controller/scheduler/grp.cpp b/DRAMSys/library/src/controller/scheduler/Grp_rename.cpp similarity index 92% rename from DRAMSys/library/src/controller/scheduler/grp.cpp rename to DRAMSys/library/src/controller/scheduler/Grp_rename.cpp index afb06fac..aa6c49cf 100644 --- a/DRAMSys/library/src/controller/scheduler/grp.cpp +++ b/DRAMSys/library/src/controller/scheduler/Grp_rename.cpp @@ -33,14 +33,14 @@ * Matthias Jung */ -#include "grp.h" +#include "Grp.h" -// GRP just reorders w.r.t. read write grouping, however is not aware of the -// row buffer. For a row buffer aware grouper refer to FR_FCFS_GRP. +// Grp (Grouper) just reorders w.r.t. read write grouping, however is not aware of the +// row buffer. For a row buffer aware grouper refer to FrFcfsGrp. // TODO: what is missed is a check if the buffers are full. This will only work // if we have buffers with a fixed size (Prado's future patch). -std::pair GRP::getNextRequest(Bank bank) +std::pair Grp::getNextRequest(Bank bank) { // If the bank is empty we do nothing: if (buffer[bank].empty()) { @@ -131,12 +131,12 @@ std::pair GRP::getNextRequest(Bank bank) readMode = !readMode; return getNextRequest(bank); - reportFatal("GRP", "Never should go here ..."); + reportFatal("Grp", "Never should go here ..."); } // There is a hazard if a read is found which will be scheduled before a write // to the same column and the same row of the same bank: -bool GRP::hazardDetection(Bank bank, std::deque::iterator ext) +bool Grp::hazardDetection(Bank bank, std::deque::iterator ext) { gp *read = *ext; @@ -157,7 +157,7 @@ bool GRP::hazardDetection(Bank bank, std::deque::iterator ext) } // Estimate the number of writes/reads in all bank buffers: -unsigned int GRP::getNumberOfRequest(tlm::tlm_command cmd) +unsigned int Grp::getNumberOfRequest(tlm::tlm_command cmd) { unsigned int numberOfRequests = 0; for (unsigned int i = 0; @@ -174,7 +174,7 @@ unsigned int GRP::getNumberOfRequest(tlm::tlm_command cmd) return numberOfRequests; } -void GRP::printDebugMessage(std::string message) +void Grp::printDebugMessage(std::string message) { - DebugManager::getInstance().printDebugMessage("FR_FCFS_GRP", message); + DebugManager::getInstance().printDebugMessage("FrFcfsGrp", message); } diff --git a/DRAMSys/library/src/controller/scheduler/grp.h b/DRAMSys/library/src/controller/scheduler/Grp_rename.h similarity index 89% rename from DRAMSys/library/src/controller/scheduler/grp.h rename to DRAMSys/library/src/controller/scheduler/Grp_rename.h index 2ffc46e0..13ccea71 100644 --- a/DRAMSys/library/src/controller/scheduler/grp.h +++ b/DRAMSys/library/src/controller/scheduler/Grp_rename.h @@ -33,29 +33,24 @@ * Matthias Jung */ -#ifndef GROUPER_H -#define GROUPER_H +#ifndef GRP_H +#define GRP_H -#include "Fr_Fcfs.h" +#include "FrFcfs.h" #include "../Controller.h" class Controller; -class GRP : public FR_FCFS +class Grp : public FrFcfs { public: - GRP(ControllerCore &controllerCore, Controller *c) : - FR_FCFS(controllerCore), - ctrl(c), - readMode(true) - { - } + Grp(ControllerCore &controllerCore, Controller *c) + : FrFcfs(controllerCore), ctrl(c), readMode(true) {} std::pair getNextRequest(Bank bank) override; private: - Controller *ctrl; bool hazardDetection(Bank bank, std::deque::iterator ext); unsigned int getNumberOfRequest(tlm::tlm_command cmd); @@ -63,4 +58,4 @@ private: bool readMode; }; -#endif // GROUPER_H +#endif // GRP_H From 193893c23b362e06d33277265c6c6655bf6d075b Mon Sep 17 00:00:00 2001 From: Lukas Steiner Date: Wed, 12 Jun 2019 00:54:02 +0200 Subject: [PATCH 74/97] Renaming of schedulers. --- DRAMSys/library/library.pro | 22 +++++++------------ DRAMSys/library/src/controller/Controller.cpp | 8 +++---- DRAMSys/library/src/controller/Controller.h | 6 ++--- .../scheduler/{Fr_Fcfs.cpp => FrFcfs.cpp} | 14 ++++++------ .../scheduler/{Fr_Fcfs.h => FrFcfs.h} | 18 +++++++-------- .../{Fr_Fcfs_grouper.cpp => FrFcfsGrp.cpp} | 19 ++++++++-------- .../{Fr_Fcfs_grouper.h => FrFcfsGrp.h} | 19 ++++++---------- ...Fr_Fcfs_read_priority.cpp => FrFcfsRp.cpp} | 17 +++++++------- .../{Fr_Fcfs_read_priority.h => FrFcfsRp.h} | 14 +++++------- .../scheduler/{Grp_rename.cpp => Grp.cpp} | 0 .../scheduler/{Grp_rename.h => Grp.h} | 0 11 files changed, 62 insertions(+), 75 deletions(-) rename DRAMSys/library/src/controller/scheduler/{Fr_Fcfs.cpp => FrFcfs.cpp} (91%) rename DRAMSys/library/src/controller/scheduler/{Fr_Fcfs.h => FrFcfs.h} (87%) rename DRAMSys/library/src/controller/scheduler/{Fr_Fcfs_grouper.cpp => FrFcfsGrp.cpp} (92%) rename DRAMSys/library/src/controller/scheduler/{Fr_Fcfs_grouper.h => FrFcfsGrp.h} (87%) rename DRAMSys/library/src/controller/scheduler/{Fr_Fcfs_read_priority.cpp => FrFcfsRp.cpp} (90%) rename DRAMSys/library/src/controller/scheduler/{Fr_Fcfs_read_priority.h => FrFcfsRp.h} (89%) rename DRAMSys/library/src/controller/scheduler/{Grp_rename.cpp => Grp.cpp} (100%) rename DRAMSys/library/src/controller/scheduler/{Grp_rename.h => Grp.h} (100%) diff --git a/DRAMSys/library/library.pro b/DRAMSys/library/library.pro index 8063b653..e4e8eedb 100644 --- a/DRAMSys/library/library.pro +++ b/DRAMSys/library/library.pro @@ -95,9 +95,7 @@ SOURCES += \ src/controller/core/powerdown/PowerDownManagerTimeout.cpp \ src/controller/core/powerdown/PowerDownManagerBankwise.cpp \ src/controller/core/powerdown/PowerDownManager.cpp \ - src/controller/scheduler/ThreadLoad.cpp \ - src/controller/scheduler/PARBS.cpp \ - src/controller/scheduler/Fr_Fcfs.cpp \ + src/controller/scheduler/FrFcfs.cpp \ src/controller/scheduler/Fifo.cpp \ src/controller/scheduler/SMS.cpp \ src/controller/core/refresh/RefreshManagerBankwise.cpp \ @@ -118,7 +116,6 @@ SOURCES += \ src/controller/core/ControllerCore.cpp \ src/simulation/MemoryManager.cpp \ src/simulation/TemperatureController.cpp \ - src/controller/scheduler/readwritegrouper.cpp \ src/controller/core/configuration/ConfigurationLoader.cpp \ src/controller/core/powerdown/NoPowerDown.cpp \ src/controller/Command.cpp \ @@ -138,11 +135,11 @@ SOURCES += \ src/error/ECC/Word.cpp \ src/error/eccbaseclass.cpp \ src/error/ecchamming.cpp \ - src/controller/scheduler/Fr_Fcfs_read_priority.cpp \ - src/controller/scheduler/Fr_Fcfs_grouper.cpp \ + src/controller/scheduler/FrFcfsRp.cpp \ + src/controller/scheduler/FrFcfsGrp.cpp \ + src/controller/scheduler/Grp.cpp \ src/controller/RecordableController.cpp \ src/common/AddressDecoder.cpp \ - src/controller/scheduler/grp.cpp \ src/common/congenAddressDecoder.cpp \ src/simulation/Dram.cpp \ src/simulation/RecordableDram.cpp \ @@ -161,9 +158,7 @@ HEADERS += \ src/controller/core/powerdown/PowerDownManagerTimeout.h \ src/controller/core/powerdown/PowerDownManagerBankwise.h \ src/controller/core/powerdown/PowerDownManager.h \ - src/controller/scheduler/ThreadLoad.h \ - src/controller/scheduler/PARBS.h \ - src/controller/scheduler/Fr_Fcfs.h \ + src/controller/scheduler/FrFcfs.h \ src/controller/scheduler/Fifo.h \ src/controller/scheduler/SMS.h \ src/controller/Controller.h \ @@ -191,7 +186,6 @@ HEADERS += \ src/simulation/Dram.h \ src/simulation/Arbiter.h \ src/common/libDRAMPower.h \ - src/controller/scheduler/readwritegrouper.h \ src/simulation/ReorderBuffer.h \ src/controller/core/configuration/MemSpec.h \ src/controller/core/configuration/thermalSimConfig.h \ @@ -219,14 +213,14 @@ HEADERS += \ src/error/ECC/Word.h \ src/error/eccbaseclass.h \ src/error/ecchamming.h \ - src/controller/scheduler/Fr_Fcfs_read_priority.h \ - src/controller/scheduler/Fr_Fcfs_grouper.h \ + src/controller/scheduler/FrFcfsRp.h \ + src/controller/scheduler/FrFcfsGrp.h \ + src/controller/scheduler/Grp.h \ src/simulation/IArbiter.h \ src/simulation/SimpleArbiter.h \ src/controller/RecordableController.h \ src/simulation/RecordableDram.h \ src/common/AddressDecoder.h \ - src/controller/scheduler/grp.h \ src/common/congenAddressDecoder.h #src/common/third_party/json/include/nlohmann/json.hpp \ diff --git a/DRAMSys/library/src/controller/Controller.cpp b/DRAMSys/library/src/controller/Controller.cpp index 27055763..242bde35 100644 --- a/DRAMSys/library/src/controller/Controller.cpp +++ b/DRAMSys/library/src/controller/Controller.cpp @@ -61,13 +61,13 @@ void Controller::buildScheduler() } else if (selectedScheduler == "FIFO_STRICT") { scheduler = new FifoStrict(*this, *controllerCore); } else if (selectedScheduler == "FR_FCFS") { - scheduler = new FR_FCFS(*controllerCore); + scheduler = new FrFcfs(*controllerCore); } else if (selectedScheduler == "FR_FCFS_RP") { - scheduler = new FR_FCFS_RP(*controllerCore); + scheduler = new FrFcfsRp(*controllerCore); } else if (selectedScheduler == "FR_FCFS_GRP") { - scheduler = new FR_FCFS_GRP(*controllerCore, this); + scheduler = new FrFcfsGrp(*controllerCore, this); } else if (selectedScheduler == "GRP") { - scheduler = new GRP(*controllerCore, this); + scheduler = new Grp(*controllerCore, this); } else if (selectedScheduler == "SMS") { scheduler = new SMS("SMS", *controllerCore, Configuration::getInstance().SJFProbability); diff --git a/DRAMSys/library/src/controller/Controller.h b/DRAMSys/library/src/controller/Controller.h index 8df4f8b0..f26e2fb8 100644 --- a/DRAMSys/library/src/controller/Controller.h +++ b/DRAMSys/library/src/controller/Controller.h @@ -67,9 +67,9 @@ #include "scheduler/Fifo.h" #include "scheduler/grp.h" #include "scheduler/FifoStrict.h" -#include "scheduler/Fr_Fcfs.h" -#include "scheduler/Fr_Fcfs_read_priority.h" -#include "scheduler/Fr_Fcfs_grouper.h" +#include "scheduler/FrFcfs.h" +#include "scheduler/FrFcfsRp.h" +#include "scheduler/FrFcfsGrp.h" #include "scheduler/SMS.h" #include "scheduler/IScheduler.h" diff --git a/DRAMSys/library/src/controller/scheduler/Fr_Fcfs.cpp b/DRAMSys/library/src/controller/scheduler/FrFcfs.cpp similarity index 91% rename from DRAMSys/library/src/controller/scheduler/Fr_Fcfs.cpp rename to DRAMSys/library/src/controller/scheduler/FrFcfs.cpp index 7fe82b7c..c51b9192 100644 --- a/DRAMSys/library/src/controller/scheduler/Fr_Fcfs.cpp +++ b/DRAMSys/library/src/controller/scheduler/FrFcfs.cpp @@ -35,17 +35,17 @@ * Matthias Jung */ -#include "Fr_Fcfs.h" +#include "FrFcfs.h" #include "../../common/dramExtension.h" #include "../core/configuration/Configuration.h" #include using namespace std; -// The FR_FCFS is descibed in a 2000 paper from Rixner et al.: +// The FrFcfs (First Ready First Come First Served) is descibed in a 2000 paper from Rixner et al.: // Memory Access Scheduling // -// The FR_FCFS scheduler features for each bank in the DRAM a specific +// The FrFcfs scheduler features for each bank in the DRAM a specific // scheduling buffer for example: // // Bank0: OOOOOOOO @@ -58,7 +58,7 @@ using namespace std; // Bank6: OOOOO0XX // Bank7: XXXXXXXX -void FR_FCFS::storeRequest(gp *payload) +void FrFcfs::storeRequest(gp *payload) { // FIXME: Question: what if the buffer is full? IMHO the schedule function // should provide a true or false when the placement into the buffer worked @@ -67,7 +67,7 @@ void FR_FCFS::storeRequest(gp *payload) .emplace_back(payload); } -std::pair FR_FCFS::getNextRequest(Bank bank) +std::pair FrFcfs::getNextRequest(Bank bank) { // If the bank is empty like Bank0 in the example we do nothing if (buffer[bank].empty()) { @@ -97,7 +97,7 @@ std::pair FR_FCFS::getNextRequest(Bank bank) // deque container. The past-the-end element is the theoretical element that // would follow the last element in the deque container. It does not point to // any element, and thus shall not be dereferenced. -deque::iterator FR_FCFS::FindRowHit(Bank bank) +deque::iterator FrFcfs::FindRowHit(Bank bank) { deque &queue = buffer[bank]; @@ -117,7 +117,7 @@ deque::iterator FR_FCFS::FindRowHit(Bank bank) return queue.end(); } -gp *FR_FCFS::getPendingRequest(Bank /*bank*/) +gp *FrFcfs::getPendingRequest(Bank /*bank*/) { return NULL; } diff --git a/DRAMSys/library/src/controller/scheduler/Fr_Fcfs.h b/DRAMSys/library/src/controller/scheduler/FrFcfs.h similarity index 87% rename from DRAMSys/library/src/controller/scheduler/Fr_Fcfs.h rename to DRAMSys/library/src/controller/scheduler/FrFcfs.h index 983c664a..ea8d250e 100644 --- a/DRAMSys/library/src/controller/scheduler/Fr_Fcfs.h +++ b/DRAMSys/library/src/controller/scheduler/FrFcfs.h @@ -35,8 +35,8 @@ * Matthias Jung */ -#ifndef FR_FCFS_H_ -#define FR_FCFS_H_ +#ifndef FRFCFS_H_ +#define FRFCFS_H_ #include "IScheduler.h" #include "../core/ControllerCore.h" @@ -44,16 +44,15 @@ #include #include - -class FR_FCFS : public IScheduler +class FrFcfs : public IScheduler { public: - FR_FCFS(ControllerCore &controllerCore) : IScheduler(controllerCore) {} - virtual ~FR_FCFS() {} + FrFcfs(ControllerCore &controllerCore) : IScheduler(controllerCore) {} + virtual ~FrFcfs() {} void storeRequest(gp *payload) override; - std::pair getNextRequest( - Bank bank) override; + std::pair + getNextRequest(Bank bank) override; virtual gp *getPendingRequest(Bank bank) override; protected: @@ -64,5 +63,4 @@ private: }; - -#endif +#endif // FRFCFS_H_ diff --git a/DRAMSys/library/src/controller/scheduler/Fr_Fcfs_grouper.cpp b/DRAMSys/library/src/controller/scheduler/FrFcfsGrp.cpp similarity index 92% rename from DRAMSys/library/src/controller/scheduler/Fr_Fcfs_grouper.cpp rename to DRAMSys/library/src/controller/scheduler/FrFcfsGrp.cpp index 9fa2030f..ef5d1bc1 100644 --- a/DRAMSys/library/src/controller/scheduler/Fr_Fcfs_grouper.cpp +++ b/DRAMSys/library/src/controller/scheduler/FrFcfsGrp.cpp @@ -33,14 +33,15 @@ * Matthias Jung */ -#include "Fr_Fcfs_grouper.h" +#include "FrFcfsGrp.h" -// The FR_FCFS_Read_Priority works exactly like the FR_FCFS_RP. -// However writes are grouped! For detailed documentation look into the FR_FCFS. +// The FrFcfsGrp (First Ready First Come First Served Grouper) works exactly +// like the FrFcfsRp (First Ready First Come First Served Read Priority). +// However writes are grouped! For detailed documentation look into the FrFcfs. // TODO: what is missed is a check if the buffers are full. This will only work // if we have buffers with a fixed size (Prado's future patch). -std::pair FR_FCFS_GRP::getNextRequest(Bank bank) +std::pair FrFcfsGrp::getNextRequest(Bank bank) { // If the bank is empty we do nothing: if (buffer[bank].empty()) { @@ -144,12 +145,12 @@ std::pair FR_FCFS_GRP::getNextRequest(Bank bank) readMode = !readMode; return getNextRequest(bank); - reportFatal("FR_FCFS_GRP", "Never should go here ..."); + reportFatal("FrFcfsGrp", "Never should go here ..."); } // There is a hazard if a read is found which will be scheduled before a write // to the same column and the same row of the same bank: -bool FR_FCFS_GRP::hazardDetection(Bank bank, std::deque::iterator ext) +bool FrFcfsGrp::hazardDetection(Bank bank, std::deque::iterator ext) { gp *read = *ext; @@ -170,7 +171,7 @@ bool FR_FCFS_GRP::hazardDetection(Bank bank, std::deque::iterator ext) } // Estimate the number of writes/reads in all bank buffers: -unsigned int FR_FCFS_GRP::getNumberOfRequest(tlm::tlm_command cmd) +unsigned int FrFcfsGrp::getNumberOfRequest(tlm::tlm_command cmd) { unsigned int numberOfRequests = 0; for (unsigned int i = 0; @@ -187,7 +188,7 @@ unsigned int FR_FCFS_GRP::getNumberOfRequest(tlm::tlm_command cmd) return numberOfRequests; } -void FR_FCFS_GRP::printDebugMessage(std::string message) +void FrFcfsGrp::printDebugMessage(std::string message) { - DebugManager::getInstance().printDebugMessage("FR_FCFS_GRP", message); + DebugManager::getInstance().printDebugMessage("FrFcfsGrp", message); } diff --git a/DRAMSys/library/src/controller/scheduler/Fr_Fcfs_grouper.h b/DRAMSys/library/src/controller/scheduler/FrFcfsGrp.h similarity index 87% rename from DRAMSys/library/src/controller/scheduler/Fr_Fcfs_grouper.h rename to DRAMSys/library/src/controller/scheduler/FrFcfsGrp.h index 6ae8ff08..ffcf0b5a 100644 --- a/DRAMSys/library/src/controller/scheduler/Fr_Fcfs_grouper.h +++ b/DRAMSys/library/src/controller/scheduler/FrFcfsGrp.h @@ -33,29 +33,24 @@ * Matthias Jung */ -#ifndef FR_FCFS_GROUPER_H -#define FR_FCFS_GROUPER_H +#ifndef FRFCFSGRP_H +#define FRFCFSGRP_H -#include "Fr_Fcfs.h" +#include "FrFcfs.h" #include "../Controller.h" class Controller; -class FR_FCFS_GRP : public FR_FCFS +class FrFcfsGrp : public FrFcfs { public: - FR_FCFS_GRP(ControllerCore &controllerCore, Controller *c) : - FR_FCFS(controllerCore), - ctrl(c), - readMode(true) - { - } + FrFcfsGrp(ControllerCore &controllerCore, Controller *c) + : FrFcfs(controllerCore), ctrl(c), readMode(true) {} std::pair getNextRequest(Bank bank) override; private: - Controller *ctrl; bool hazardDetection(Bank bank, std::deque::iterator ext); unsigned int getNumberOfRequest(tlm::tlm_command cmd); @@ -63,4 +58,4 @@ private: bool readMode; }; -#endif // FR_FCFS_GROUPER_H +#endif // FRFCFSGRP_H diff --git a/DRAMSys/library/src/controller/scheduler/Fr_Fcfs_read_priority.cpp b/DRAMSys/library/src/controller/scheduler/FrFcfsRp.cpp similarity index 90% rename from DRAMSys/library/src/controller/scheduler/Fr_Fcfs_read_priority.cpp rename to DRAMSys/library/src/controller/scheduler/FrFcfsRp.cpp index 117583c6..250510c0 100644 --- a/DRAMSys/library/src/controller/scheduler/Fr_Fcfs_read_priority.cpp +++ b/DRAMSys/library/src/controller/scheduler/FrFcfsRp.cpp @@ -33,12 +33,13 @@ * Matthias Jung */ -#include "Fr_Fcfs_read_priority.h" +#include "FrFcfsRp.h" -// The FR_FCFS_Read_Priority works exactly like the FR_FCFS but reads are -// prioratized over writes. For detailed documentation look into the FR_FCFS. +// The FrFcfsRp (First Ready First Come First Served Read Priority) works +// exactly like the FrFcfs but reads are prioratized over writes. +// For detailed documentation look into the FrFcfs. -std::pair FR_FCFS_RP::getNextRequest(Bank bank) +std::pair FrFcfsRp::getNextRequest(Bank bank) { // If the bank is empty like Bank0 in the example we do nothing: if (buffer[bank].empty()) { @@ -107,13 +108,13 @@ std::pair FR_FCFS_RP::getNextRequest(Bank bank) } } - reportFatal("FR_FCFS_RP", "Never should go here ..."); + reportFatal("FrFcfsRp", "Never should go here ..."); return pair(Command::NOP, NULL); } // There is a hazard if a read is found which will be scheduled before a write // to the same column and the same row of the same bank: -bool FR_FCFS_RP::hazardDetection(Bank bank, std::deque::iterator ext) +bool FrFcfsRp::hazardDetection(Bank bank, std::deque::iterator ext) { gp *read = *ext; @@ -133,7 +134,7 @@ bool FR_FCFS_RP::hazardDetection(Bank bank, std::deque::iterator ext) return false; } -void FR_FCFS_RP::printDebugMessage(std::string message) +void FrFcfsRp::printDebugMessage(std::string message) { - DebugManager::getInstance().printDebugMessage("FR_FCFS_RP", message); + DebugManager::getInstance().printDebugMessage("FrFcfsRp", message); } diff --git a/DRAMSys/library/src/controller/scheduler/Fr_Fcfs_read_priority.h b/DRAMSys/library/src/controller/scheduler/FrFcfsRp.h similarity index 89% rename from DRAMSys/library/src/controller/scheduler/Fr_Fcfs_read_priority.h rename to DRAMSys/library/src/controller/scheduler/FrFcfsRp.h index fac0af85..c1c10ca4 100644 --- a/DRAMSys/library/src/controller/scheduler/Fr_Fcfs_read_priority.h +++ b/DRAMSys/library/src/controller/scheduler/FrFcfsRp.h @@ -33,23 +33,21 @@ * Matthias Jung */ -#ifndef FR_FCFS_READ_PRIORITY_H -#define FR_FCFS_READ_PRIORITY_H +#ifndef FRFCFSRP_H +#define FRFCFSRP_H -#include "Fr_Fcfs.h" +#include "FrFcfs.h" -class FR_FCFS_RP : public FR_FCFS +class FrFcfsRp : public FrFcfs { public: - FR_FCFS_RP(ControllerCore &controllerCore) : FR_FCFS(controllerCore) {} - + FrFcfsRp(ControllerCore &controllerCore) : FrFcfs(controllerCore) {} std::pair getNextRequest(Bank bank) override; private: - bool hazardDetection(Bank bank, std::deque::iterator ext); void printDebugMessage(std::string message); }; -#endif // FR_FCFS_READ_PRIORITY_H +#endif // FRFCFSRP_H diff --git a/DRAMSys/library/src/controller/scheduler/Grp_rename.cpp b/DRAMSys/library/src/controller/scheduler/Grp.cpp similarity index 100% rename from DRAMSys/library/src/controller/scheduler/Grp_rename.cpp rename to DRAMSys/library/src/controller/scheduler/Grp.cpp diff --git a/DRAMSys/library/src/controller/scheduler/Grp_rename.h b/DRAMSys/library/src/controller/scheduler/Grp.h similarity index 100% rename from DRAMSys/library/src/controller/scheduler/Grp_rename.h rename to DRAMSys/library/src/controller/scheduler/Grp.h From 6bc5f6ead3fe0909a4333a01e9db96ca76b75d63 Mon Sep 17 00:00:00 2001 From: Lukas Steiner Date: Wed, 12 Jun 2019 00:54:55 +0200 Subject: [PATCH 75/97] Removed unused files in folder scheduler. --- .../src/controller/scheduler/PARBS.cpp | 149 -------------- .../library/src/controller/scheduler/PARBS.h | 77 ------- .../src/controller/scheduler/ThreadLoad.cpp | 108 ---------- .../src/controller/scheduler/ThreadLoad.h | 81 -------- .../controller/scheduler/readwritegrouper.cpp | 191 ------------------ .../controller/scheduler/readwritegrouper.h | 78 ------- 6 files changed, 684 deletions(-) delete mode 100644 DRAMSys/library/src/controller/scheduler/PARBS.cpp delete mode 100644 DRAMSys/library/src/controller/scheduler/PARBS.h delete mode 100644 DRAMSys/library/src/controller/scheduler/ThreadLoad.cpp delete mode 100644 DRAMSys/library/src/controller/scheduler/ThreadLoad.h delete mode 100644 DRAMSys/library/src/controller/scheduler/readwritegrouper.cpp delete mode 100644 DRAMSys/library/src/controller/scheduler/readwritegrouper.h diff --git a/DRAMSys/library/src/controller/scheduler/PARBS.cpp b/DRAMSys/library/src/controller/scheduler/PARBS.cpp deleted file mode 100644 index fcc65896..00000000 --- a/DRAMSys/library/src/controller/scheduler/PARBS.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2015, University of Kaiserslautern - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: - * Janik Schlemminger - * Robert Gernhardt - * Matthias Jung - */ - - -//// * PARBS.cpp -//// * -//// * Created on: Apr 9, 2014 -//// * Author: robert -//// */ - -//#include "PARBS.h" -//#include "../core/configuration/Configuration.h" -//#include "../../common/dramExtension.h" -//#include "map" -//#include "ThreadLoad.h" -//#include - -//namespace scheduler { - -//using namespace std; - -//PAR_BS::PAR_BS(ControllerCore& controllerCore, bool useExternalBankstates, unsigned int capsize) : -// controllerCore(controllerCore), useExternalBankstates(useExternalBankstates), capsize(capsize) -//{ -// if (useExternalBankstates) -// { -// batch = new FR_FCFS(controllerCore, true, false); -// buffer = new FR_FCFS(controllerCore, true, false); -// } -// else -// { -// batch = new FR_FCFS(controllerCore, true, false); -// buffer = new FR_FCFS(controllerCore, true, false); -// } -//} - -//PAR_BS::~PAR_BS() -//{ - -//} - -//bool PAR_BS::hasPayloads() -//{ -// return batch->hasPayloads() || buffer->hasPayloads(); -//} - -//void PAR_BS::schedule(gp* payload) -//{ -// printDebugMessage("hello!"); -// buffer->schedule(payload); -//} - -//gp* PAR_BS::getNextPayload() -//{ -// if (!batch->hasPayloads()) -// { -// stringstream s; -// s << "In batch: " << batch->getNumberOfQueuedPayloads() << "\t" << "in buffer: " << buffer->getNumberOfQueuedPayloads() << endl; -// formBatch(); -// s<< "Formed new batch" << endl; -// s << "In batch: " << batch->getNumberOfQueuedPayloads() << "\t" << "in buffer: " << buffer->getNumberOfQueuedPayloads() << endl; -// printDebugMessage(s.str()); -// sc_assert(batch->hasPayloads()); -// } - -// gp* result = batch->getNextPayload(); -// if(result == NULL) -// result = buffer->getNextPayload(); -// return result; -//} - -//void PAR_BS::removePayload(gp* payload) -//{ -// buffer->removePayload(payload); -// batch->removePayload(payload); - -// if (!useExternalBankstates) -// { -// DramExtension& extension = DramExtension::getExtension(payload); -// internalBankstates.openRowInRowBuffer(extension.getBank(), extension.getRow()); -// } - -//} - -//void PAR_BS::formBatch() -//{ -// map loads; - -// for (Bank bank : controllerCore.getBanks()) -// { -// for (unsigned int i = 0; i < capsize; i++) -// { -// gp* payload = buffer->popOldest(bank); -// if(payload == NULL) -// break; -// loads[DramExtension::getExtension(payload).getThread()].addTransaction(payload); -// } -// } - -// vector sortedLoads; -// for (auto& threadLoadPair : loads) -// { -// sortedLoads.push_back(&threadLoadPair.second); -// } - -// sort(sortedLoads.begin(), sortedLoads.end(), LoadPointerComparer()); - -// for (auto& load : sortedLoads) -// { -// batch->schedule(load->getTransactions()); -// } - -//} - -//} diff --git a/DRAMSys/library/src/controller/scheduler/PARBS.h b/DRAMSys/library/src/controller/scheduler/PARBS.h deleted file mode 100644 index 59e3f1e1..00000000 --- a/DRAMSys/library/src/controller/scheduler/PARBS.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2015, University of Kaiserslautern - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: - * Janik Schlemminger - * Robert Gernhardt - * Matthias Jung - */ - - -//// * PARBS.h -//// * -//// * Created on: Apr 9, 2014 -//// * Author: robert -//// * - -//#ifndef PARBS_H_ -//#define PARBS_H_ -//#include "Scheduler.h" -//#include "../core/ControllerCore.h" -//#include "Fr_Fcfs.h" - -//namespace scheduler { - -//class PAR_BS : public Scheduler -//{ -//public: -// PAR_BS(ControllerCore& controllerCore, bool useExternalBankstates, unsigned int capsize); -// virtual ~PAR_BS(); - -// virtual bool hasPayloads() override; -// virtual void schedule(gp* payload) override; -// virtual gp* getNextPayload() override; -// virtual void removePayload(gp* payload) override; - -//private: -// void formBatch(); - -// ControllerCore& controllerCore; -// bool useExternalBankstates; -// RowBufferState internalBankstates; -// FR_FCFS *batch; -// FR_FCFS *buffer; -// unsigned int capsize; -//}; - -//} /* scheduler core */ - -//#endif diff --git a/DRAMSys/library/src/controller/scheduler/ThreadLoad.cpp b/DRAMSys/library/src/controller/scheduler/ThreadLoad.cpp deleted file mode 100644 index 1938c1d3..00000000 --- a/DRAMSys/library/src/controller/scheduler/ThreadLoad.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2015, University of Kaiserslautern - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: - * Janik Schlemminger - * Robert Gernhardt - * Matthias Jung - */ - - -// * ThreadLoad.cpp -// * -// * Created on: Apr 9, 2014 -// * Author: robert -// */ - -//#include "ThreadLoad.h" - -//namespace scheduler { - -//using namespace std; - -//ThreadLoad::ThreadLoad() -//{ -// // TODO Auto-generated constructor stub - -//} - -//ThreadLoad::~ThreadLoad() -//{ -// // TODO Auto-generated destructor stub -//} - -//unsigned int ThreadLoad::getMaxBankLoad() const -//{ -// unsigned int maxLoad = 0; -// for (auto& bankVectorPair : load) -// { -// if (bankVectorPair.second.size() > maxLoad) -// maxLoad = bankVectorPair.second.size(); -// } -// return maxLoad; -//} - -//unsigned int ThreadLoad::getTotalLoad() const -//{ -// unsigned int totalLoad = 0; -// for (auto& bankVectorPair : load) -// { -// totalLoad += bankVectorPair.second.size(); -// } -// return totalLoad; -//} - -//void ThreadLoad::addTransaction(gp* payload) -//{ -// load[DramExtension::getExtension(payload).getBank()].push_back(payload); -//} - -//bool operator<(const ThreadLoad& lhs, const ThreadLoad& rhs) -//{ -// if (lhs.getMaxBankLoad() < rhs.getMaxBankLoad()) -// return true; -// else if (lhs.getMaxBankLoad() == rhs.getMaxBankLoad()) -// return lhs.getTotalLoad() < rhs.getTotalLoad(); -// else -// return false; -//} - -//vector ThreadLoad::getTransactions() -//{ -// vector result; -// for (auto& bankVectorPair : load) -// { -// result.insert(result.end(), bankVectorPair.second.begin(), bankVectorPair.second.end()); -// } -// return result; -//} - -//} /* namespace scheduler diff --git a/DRAMSys/library/src/controller/scheduler/ThreadLoad.h b/DRAMSys/library/src/controller/scheduler/ThreadLoad.h deleted file mode 100644 index f4152a05..00000000 --- a/DRAMSys/library/src/controller/scheduler/ThreadLoad.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2015, University of Kaiserslautern - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: - * Janik Schlemminger - * Robert Gernhardt - * Matthias Jung - */ - - -//// * ThreadLoad.h -//// * -//// * Created on: Apr 9, 2014 -//// * Author: robert -//// */ - -//#ifndef THREADLOAD_H_ -//#define THREADLOAD_H_ -//#include -//#include -//#include "../../common/dramExtension.h" - -//namespace scheduler { - -//typedef tlm::tlm_generic_payload gp; - -//class ThreadLoad -//{ -//public: -// ThreadLoad();d -// virtual ~ThreadLoad(); - -// unsigned int getMaxBankLoad() const; -// unsigned int getTotalLoad() const; - -// void addTransaction(gp* payload); -// std::vector getTransactions(); - -//private: -// std::map> load; -//}; - -//bool operator< (const ThreadLoad &lhs, const ThreadLoad &rhs); - -//struct LoadPointerComparer { -// bool operator()(const ThreadLoad* l, const ThreadLoad* r) { -// return *l < *r; -// } -//}; - -//} /* namespace scheduler */ - -//#endif /* THREADLOAD_H_ diff --git a/DRAMSys/library/src/controller/scheduler/readwritegrouper.cpp b/DRAMSys/library/src/controller/scheduler/readwritegrouper.cpp deleted file mode 100644 index e290fddd..00000000 --- a/DRAMSys/library/src/controller/scheduler/readwritegrouper.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) 2015, University of Kaiserslautern - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: - * Janik Schlemminger - * Robert Gernhardt - * Matthias Jung - */ - -//#include "readwritegrouper.h" -//#include "../../common/DebugManager.h" - -//namespace scheduler{ - -//using namespace tlm; -//using namespace std; - -//ReadWriteGrouper::ReadWriteGrouper(ControllerCore& controllerCore): controllerCore(controllerCore) -//{ -// batches.push_back(shared_ptr(new FR_FCFS(controllerCore,true,false))); -// batches.push_back(shared_ptr(new FR_FCFS(controllerCore,true,false))); -//} - -//ReadWriteGrouper::~ReadWriteGrouper() -//{ - -//} - -//void ReadWriteGrouper::schedule(gp *payload) -//{ -// tlm_command command = payload->get_command(); - -// if(batches.size() > 2) -// { -// if(command == TLM_READ_COMMAND) -// { -// //printDebugMessage("Scheduling read"); - -// if(schedulingReadCausesHazardWithQueuedWrite(payload)) -// { -// printDebugMessage("Scheduling read causes hazard with queued write"); -// batches.push_back(shared_ptr(new FR_FCFS(controllerCore,true,false))); -// batches.push_back(shared_ptr(new FR_FCFS(controllerCore,true,false))); -// } - -// getLatestReadBatch().schedule(payload); -// } -// else if(command == TLM_WRITE_COMMAND) -// { -// //printDebugMessage("Scheduling write"); -// getLatestWriteBatch().schedule(payload); -// } -// } -// else if(batches.size() == 2) -// { -// if(command == TLM_READ_COMMAND) -// { -// //printDebugMessage("Scheduling read"); - -// if(getLatestReadBatch().hasPayloads() && schedulingReadCausesHazardWithQueuedWrite(payload)) -// { -// printDebugMessage("Scheduling read causes hazard with queued write"); -// batches.push_back(shared_ptr(new FR_FCFS(controllerCore,true,false))); -// batches.push_back(shared_ptr(new FR_FCFS(controllerCore,true,false))); -// } -// else if(!getLatestReadBatch().hasPayloads() && getLatestWriteBatch().hasPayloads()) -// { -// printDebugMessage("Scheduling read, but there are writes to be processed first"); -// batches.erase(batches.begin()); -// batches.push_back(shared_ptr(new FR_FCFS(controllerCore,true,false))); -// batches.push_back(shared_ptr(new FR_FCFS(controllerCore,true,false))); -// } -// getLatestReadBatch().schedule(payload); - -// } -// else if(command == TLM_WRITE_COMMAND) -// { -// //printDebugMessage("Scheduling write"); -// getLatestWriteBatch().schedule(payload); -// } -// } -// else -// { -// sc_assert(false); -// } -//} - -//gp *ReadWriteGrouper::getNextPayload() -//{ -// if(batches.size() > 2) -// { -// return batches.front()->getNextPayload(); -// } -// else if(batches.size() == 2) -// { -// if(getLatestReadBatch().hasPayloads()) -// return getLatestReadBatch().getNextPayload(); -// else if(getLatestWriteBatch().hasPayloads()) -// return getLatestWriteBatch().getNextPayload(); -// else -// return NULL; -// } -// else -// { -// sc_assert(false); -// return NULL; -// } -//} - - -//void ReadWriteGrouper::removePayload(gp *payload) -//{ -// if(batches.size() > 2) -// { -// batches.front()->removePayload(payload); -// if(!batches.front()->hasPayloads()) -// batches.erase(batches.begin()); -// } -// else if(batches.size() == 2) -// { -// if(payload->is_read()) -// getLatestReadBatch().removePayload(payload); -// else -// getLatestWriteBatch().removePayload(payload); -// } -// else -// { -// sc_assert(false); -// } -//} - - -//bool ReadWriteGrouper::hasPayloads() -//{ -// if(batches.size() > 2) -// return true; -// else if(batches.size() == 2) -// return (getLatestReadBatch().hasPayloads() || getLatestWriteBatch().hasPayloads()); -// else -// { -// sc_assert(false); -// return NULL; -// } -//} - - -//bool ReadWriteGrouper::schedulingReadCausesHazardWithQueuedWrite(gp *payload) -//{ -// sc_assert(payload->is_read()); -// return getLatestWriteBatch().containsPayloadTragetingSameAddress(payload); -//} - -//FR_FCFS &ReadWriteGrouper::getLatestWriteBatch() -//{ -// return *batches[batches.size()-1]; -//} - -//FR_FCFS &ReadWriteGrouper::getLatestReadBatch() -//{ -// return *batches[batches.size()-2]; -//} - -//} diff --git a/DRAMSys/library/src/controller/scheduler/readwritegrouper.h b/DRAMSys/library/src/controller/scheduler/readwritegrouper.h deleted file mode 100644 index 760b17fc..00000000 --- a/DRAMSys/library/src/controller/scheduler/readwritegrouper.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2015, University of Kaiserslautern - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: - * Janik Schlemminger - * Robert Gernhardt - * Matthias Jung - */ - -//#ifndef READWRITEGROUPER_H -//#define READWRITEGROUPER_H -//#include "Scheduler.h" -//#include "Fr_Fcfs.h" -//#include "../core/ControllerCore.h" -//#include -//#include - - -//namespace scheduler{ - -//class ReadWriteGrouper : public Scheduler -//{ -//public: -// ReadWriteGrouper(ControllerCore& controllerCore); -// ~ReadWriteGrouper(); -// virtual void schedule(gp* payload) override; -// virtual bool hasPayloads() override; -// virtual gp* getNextPayload() override; -// virtual void removePayload(gp* payload) override; - -//private: -// // contains batches of requests -// // last element always contains writes -// // next-to-last element always contains reads -// // there are always at least two batches -// // if there are more than two batches, batches[0] is never empty and -// // getNextPayload and removePayload are forwarded to batches[0] -// std::vector> batches; -// ControllerCore& controllerCore; - -// bool schedulingReadCausesHazardWithQueuedWrite(gp* payload); -// FR_FCFS& getLatestWriteBatch(); -// FR_FCFS& getLatestReadBatch(); - -//}; - - -//} - -//#endif // READWRITEGROUPER_H From cea3b26bd0d015dfc4f48bc4096fc04976877cd5 Mon Sep 17 00:00:00 2001 From: Lukas Steiner Date: Wed, 12 Jun 2019 01:49:27 +0200 Subject: [PATCH 76/97] Bugfix (incomplete renaming). --- DRAMSys/library/src/controller/Controller.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DRAMSys/library/src/controller/Controller.h b/DRAMSys/library/src/controller/Controller.h index f26e2fb8..3b604c63 100644 --- a/DRAMSys/library/src/controller/Controller.h +++ b/DRAMSys/library/src/controller/Controller.h @@ -65,7 +65,7 @@ #include "core/scheduling/Trigger.h" #include "core/TimingCalculation.h" #include "scheduler/Fifo.h" -#include "scheduler/grp.h" +#include "scheduler/Grp.h" #include "scheduler/FifoStrict.h" #include "scheduler/FrFcfs.h" #include "scheduler/FrFcfsRp.h" From 20797f61f517e42193dcf98ac9ea97c0b5b76d18 Mon Sep 17 00:00:00 2001 From: Lukas Steiner Date: Wed, 12 Jun 2019 16:21:00 +0200 Subject: [PATCH 77/97] Renaming files (Commit 1 of 2) --- DRAMSys/library/library.pro | 10 +++++----- DRAMSys/library/src/common/AddressDecoder.cpp | 6 +++--- DRAMSys/library/src/common/TlmRecorder.cpp | 2 +- DRAMSys/library/src/common/TlmRecorder.h | 2 +- ...Decoder.cpp => rename_CongenAddressDecoder.cpp} | 2 +- ...ressDecoder.h => rename_CongenAddressDecoder.h} | 0 ...essdecoder.cpp => rename_XmlAddressDecoder.cpp} | 14 +++++++------- ...Addressdecoder.h => rename_XmlAddressDecoder.h} | 4 ++-- .../core/configuration/Configuration.cpp | 2 +- DRAMSys/library/src/error/eccbaseclass.h | 2 +- DRAMSys/library/src/error/errormodel.h | 2 +- DRAMSys/library/src/simulation/Arbiter.h | 2 +- DRAMSys/library/src/simulation/DRAMSys.cpp | 6 +++--- DRAMSys/library/src/simulation/IArbiter.h | 12 ++++++------ DRAMSys/library/src/simulation/SimpleArbiter.h | 2 +- DRAMSys/library/src/simulation/StlPlayer.h | 2 +- DRAMSys/library/src/simulation/TracePlayer.h | 2 +- 17 files changed, 36 insertions(+), 36 deletions(-) rename DRAMSys/library/src/common/{congenAddressDecoder.cpp => rename_CongenAddressDecoder.cpp} (99%) rename DRAMSys/library/src/common/{congenAddressDecoder.h => rename_CongenAddressDecoder.h} (100%) rename DRAMSys/library/src/common/{xmlAddressdecoder.cpp => rename_XmlAddressDecoder.cpp} (92%) rename DRAMSys/library/src/common/{xmlAddressdecoder.h => rename_XmlAddressDecoder.h} (98%) diff --git a/DRAMSys/library/library.pro b/DRAMSys/library/library.pro index e4e8eedb..6ea08e13 100644 --- a/DRAMSys/library/library.pro +++ b/DRAMSys/library/library.pro @@ -86,7 +86,6 @@ QMAKE_CXXFLAGS += -isystem $${systemc_home}/include SOURCES += \ src/common/third_party/tinyxml2/tinyxml2.cpp \ - src/common/xmlAddressdecoder.cpp \ src/common/Utils.cpp \ src/common/TlmRecorder.cpp \ src/common/dramExtension.cpp \ @@ -140,14 +139,14 @@ SOURCES += \ src/controller/scheduler/Grp.cpp \ src/controller/RecordableController.cpp \ src/common/AddressDecoder.cpp \ - src/common/congenAddressDecoder.cpp \ src/simulation/Dram.cpp \ src/simulation/RecordableDram.cpp \ - src/simulation/Arbiter.cpp + src/simulation/Arbiter.cpp \ + src/common/rename_CongenAddressDecoder.cpp \ + src/common/rename_XmlAddressDecoder.cpp HEADERS += \ src/common/third_party/tinyxml2/tinyxml2.h \ - src/common/xmlAddressdecoder.h \ src/common/Utils.h \ src/common/TlmRecorder.h \ src/common/tlm2_base_protocol_checker.h \ @@ -221,7 +220,8 @@ HEADERS += \ src/controller/RecordableController.h \ src/simulation/RecordableDram.h \ src/common/AddressDecoder.h \ - src/common/congenAddressDecoder.h + src/common/rename_CongenAddressDecoder.h \ + src/common/rename_XmlAddressDecoder.h #src/common/third_party/json/include/nlohmann/json.hpp \ thermalsim = $$(THERMALSIM) diff --git a/DRAMSys/library/src/common/AddressDecoder.cpp b/DRAMSys/library/src/common/AddressDecoder.cpp index f5eb23ce..ee6b4b38 100644 --- a/DRAMSys/library/src/common/AddressDecoder.cpp +++ b/DRAMSys/library/src/common/AddressDecoder.cpp @@ -34,8 +34,8 @@ */ #include "AddressDecoder.h" -#include "xmlAddressdecoder.h" -#include "congenAddressDecoder.h" +#include "rename_XmlAddressDecoder.h" +#include "rename_CongenAddressDecoder.h" AddressDecoder *AddressDecoder::m_pInstance = nullptr; @@ -50,7 +50,7 @@ void AddressDecoder::createInstance(Type t) assert(m_pInstance == nullptr); switch (t) { case Type::XML: - m_pInstance = new xmlAddressDecoder; + m_pInstance = new XmlAddressDecoder; break; case Type::CONGEN: m_pInstance = new CongenAddressDecoder; diff --git a/DRAMSys/library/src/common/TlmRecorder.cpp b/DRAMSys/library/src/common/TlmRecorder.cpp index db59e640..3709a487 100644 --- a/DRAMSys/library/src/common/TlmRecorder.cpp +++ b/DRAMSys/library/src/common/TlmRecorder.cpp @@ -42,7 +42,7 @@ #include "TlmRecorder.h" #include "protocol.h" #include "dramExtension.h" -#include "xmlAddressdecoder.h" +#include "rename_XmlAddressDecoder.h" #include "../controller/core/configuration/Configuration.h" #include "../controller/Controller.h" diff --git a/DRAMSys/library/src/common/TlmRecorder.h b/DRAMSys/library/src/common/TlmRecorder.h index 31deb14d..150e0c3b 100644 --- a/DRAMSys/library/src/common/TlmRecorder.h +++ b/DRAMSys/library/src/common/TlmRecorder.h @@ -49,7 +49,7 @@ #include #include #include -#include "xmlAddressdecoder.h" +#include "rename_XmlAddressDecoder.h" #include "DebugManager.h" #include "Utils.h" diff --git a/DRAMSys/library/src/common/congenAddressDecoder.cpp b/DRAMSys/library/src/common/rename_CongenAddressDecoder.cpp similarity index 99% rename from DRAMSys/library/src/common/congenAddressDecoder.cpp rename to DRAMSys/library/src/common/rename_CongenAddressDecoder.cpp index 5a366741..071967f8 100644 --- a/DRAMSys/library/src/common/congenAddressDecoder.cpp +++ b/DRAMSys/library/src/common/rename_CongenAddressDecoder.cpp @@ -33,7 +33,7 @@ * Johannes Feldmann */ -#include "congenAddressDecoder.h" +#include "rename_CongenAddressDecoder.h" #include "Utils.h" #include diff --git a/DRAMSys/library/src/common/congenAddressDecoder.h b/DRAMSys/library/src/common/rename_CongenAddressDecoder.h similarity index 100% rename from DRAMSys/library/src/common/congenAddressDecoder.h rename to DRAMSys/library/src/common/rename_CongenAddressDecoder.h diff --git a/DRAMSys/library/src/common/xmlAddressdecoder.cpp b/DRAMSys/library/src/common/rename_XmlAddressDecoder.cpp similarity index 92% rename from DRAMSys/library/src/common/xmlAddressdecoder.cpp rename to DRAMSys/library/src/common/rename_XmlAddressDecoder.cpp index 11f4549c..403ac560 100644 --- a/DRAMSys/library/src/common/xmlAddressdecoder.cpp +++ b/DRAMSys/library/src/common/rename_XmlAddressDecoder.cpp @@ -35,7 +35,7 @@ * Matthias Jung */ -#include "xmlAddressdecoder.h" +#include "rename_XmlAddressDecoder.h" #include #include "Utils.h" #include "bitset" @@ -44,12 +44,12 @@ using namespace std; using namespace tinyxml2; -xmlAddressDecoder::xmlAddressDecoder() +XmlAddressDecoder::XmlAddressDecoder() { addressmapping = NULL; } -void xmlAddressDecoder::setConfiguration(std::string addressConfigURI) +void XmlAddressDecoder::setConfiguration(std::string addressConfigURI) { tinyxml2::XMLDocument doc; loadXML(addressConfigURI, doc); @@ -76,7 +76,7 @@ void xmlAddressDecoder::setConfiguration(std::string addressConfigURI) } -DecodedAddress xmlAddressDecoder::decodeAddress(sc_dt::uint64 addr) +DecodedAddress XmlAddressDecoder::decodeAddress(sc_dt::uint64 addr) { DecodedAddress result; result.channel = (addr & masks["channel"]) >> shifts["channel"]; @@ -92,7 +92,7 @@ DecodedAddress xmlAddressDecoder::decodeAddress(sc_dt::uint64 addr) return result; } -sc_dt::uint64 xmlAddressDecoder::encodeAddress(DecodedAddress n) +sc_dt::uint64 XmlAddressDecoder::encodeAddress(DecodedAddress n) { return n.channel << shifts["channel"] | n.rank << shifts["rank"] | @@ -103,7 +103,7 @@ sc_dt::uint64 xmlAddressDecoder::encodeAddress(DecodedAddress n) n.bytes << shifts["bytes"]; } -bool xmlAddressDecoder::testConfigFile(std::string url) +bool XmlAddressDecoder::testConfigFile(std::string url) { // Simple test if the root node has the correct name. // This is suitable for now, but can be extended in future. @@ -115,7 +115,7 @@ bool xmlAddressDecoder::testConfigFile(std::string url) return (strcmp(addressMap->Name(), "addressmapping") == 0); } -void xmlAddressDecoder::print() +void XmlAddressDecoder::print() { cout << headline << endl; cout << "Address Mapping:" << endl << endl; diff --git a/DRAMSys/library/src/common/xmlAddressdecoder.h b/DRAMSys/library/src/common/rename_XmlAddressDecoder.h similarity index 98% rename from DRAMSys/library/src/common/xmlAddressdecoder.h rename to DRAMSys/library/src/common/rename_XmlAddressDecoder.h index de1e574c..6f87bcd5 100644 --- a/DRAMSys/library/src/common/xmlAddressdecoder.h +++ b/DRAMSys/library/src/common/rename_XmlAddressDecoder.h @@ -44,7 +44,7 @@ #include "third_party/tinyxml2/tinyxml2.h" #include "AddressDecoder.h" -class xmlAddressDecoder +class XmlAddressDecoder : private AddressDecoder { // Friendship needed so that the AddressDecoder can access the @@ -58,7 +58,7 @@ private: tinyxml2::XMLElement *addressmapping; public: - xmlAddressDecoder(); + XmlAddressDecoder(); virtual DecodedAddress decodeAddress(sc_dt::uint64 addr); virtual sc_dt::uint64 encodeAddress(DecodedAddress n); diff --git a/DRAMSys/library/src/controller/core/configuration/Configuration.cpp b/DRAMSys/library/src/controller/core/configuration/Configuration.cpp index 50f5d563..fa69feae 100644 --- a/DRAMSys/library/src/controller/core/configuration/Configuration.cpp +++ b/DRAMSys/library/src/controller/core/configuration/Configuration.cpp @@ -40,7 +40,7 @@ #include "Configuration.h" #include "ConfigurationLoader.h" -#include "../../../common/xmlAddressdecoder.h" +#include "../../../common/rename_XmlAddressDecoder.h" using namespace std; diff --git a/DRAMSys/library/src/error/eccbaseclass.h b/DRAMSys/library/src/error/eccbaseclass.h index 544eb420..4219d8c3 100644 --- a/DRAMSys/library/src/error/eccbaseclass.h +++ b/DRAMSys/library/src/error/eccbaseclass.h @@ -8,7 +8,7 @@ #include "ECC/ECC.h" -#include "../common/xmlAddressdecoder.h" +#include "../common/rename_XmlAddressDecoder.h" #include "../common/DebugManager.h" using namespace std; diff --git a/DRAMSys/library/src/error/errormodel.h b/DRAMSys/library/src/error/errormodel.h index c1f21c6e..5f942b14 100644 --- a/DRAMSys/library/src/error/errormodel.h +++ b/DRAMSys/library/src/error/errormodel.h @@ -40,7 +40,7 @@ #include #include #include "../controller/core/configuration/Configuration.h" -#include "../common/xmlAddressdecoder.h" +#include "../common/rename_XmlAddressDecoder.h" #include "../common/third_party/DRAMPower/src/libdrampower/LibDRAMPower.h" class errorModel : public sc_module diff --git a/DRAMSys/library/src/simulation/Arbiter.h b/DRAMSys/library/src/simulation/Arbiter.h index 1c5687b0..feeedec3 100644 --- a/DRAMSys/library/src/simulation/Arbiter.h +++ b/DRAMSys/library/src/simulation/Arbiter.h @@ -46,7 +46,7 @@ #include #include #include -#include "../common/xmlAddressdecoder.h" +#include "../common/rename_XmlAddressDecoder.h" #include "../common/dramExtension.h" #include "../controller/core/TimingCalculation.h" #include "../controller/core/configuration/ConfigurationLoader.h" diff --git a/DRAMSys/library/src/simulation/DRAMSys.cpp b/DRAMSys/library/src/simulation/DRAMSys.cpp index 30b2393e..dc798194 100644 --- a/DRAMSys/library/src/simulation/DRAMSys.cpp +++ b/DRAMSys/library/src/simulation/DRAMSys.cpp @@ -46,8 +46,8 @@ #include "Setup.h" #include "../common/TlmRecorder.h" #include "../common/DebugManager.h" -#include "../common/xmlAddressdecoder.h" -#include "../common/congenAddressDecoder.h" +#include "../common/rename_XmlAddressDecoder.h" +#include "../common/rename_CongenAddressDecoder.h" #include "../controller/core/ControllerCore.h" #include "../controller/core/configuration/ConfigurationLoader.h" #include "../common/Utils.h" @@ -86,7 +86,7 @@ DRAMSys::DRAMSys(sc_module_name __attribute__((unused)) name, // ConfigurationLoader because some information from the xmlAddressDecoder // is needed to assure the coherence of the configuration. - if (xmlAddressDecoder::testConfigFile(pathToResources + "configs/amconfigs/" + + if (XmlAddressDecoder::testConfigFile(pathToResources + "configs/amconfigs/" + amconfig)) { AddressDecoder::createInstance(AddressDecoder::Type::XML); AddressDecoder::getInstance().setConfiguration(pathToResources diff --git a/DRAMSys/library/src/simulation/IArbiter.h b/DRAMSys/library/src/simulation/IArbiter.h index 3c3460cc..88c1231b 100644 --- a/DRAMSys/library/src/simulation/IArbiter.h +++ b/DRAMSys/library/src/simulation/IArbiter.h @@ -101,7 +101,7 @@ protected: payload.set_auto_extension(genExtension); unsigned int burstlength = payload.get_streaming_width(); - DecodedAddress decodedAddress = xmlAddressDecoder::getInstance().decodeAddress( + DecodedAddress decodedAddress = XmlAddressDecoder::getInstance().decodeAddress( payload.get_address()); // Check the valid range of decodedAddress if (addressIsValid(decodedAddress)) { @@ -118,21 +118,21 @@ protected: bool addressIsValid(DecodedAddress &decodedAddress) { if (decodedAddress.channel >= - xmlAddressDecoder::getInstance().amount["channel"]) { + XmlAddressDecoder::getInstance().amount["channel"]) { return false; } - if (decodedAddress.bank >= xmlAddressDecoder::getInstance().amount["bank"]) { + if (decodedAddress.bank >= XmlAddressDecoder::getInstance().amount["bank"]) { return false; } if (decodedAddress.bankgroup > - xmlAddressDecoder::getInstance().amount["bankgroup"]) { + XmlAddressDecoder::getInstance().amount["bankgroup"]) { return false; } if (decodedAddress.column >= - xmlAddressDecoder::getInstance().amount["column"]) { + XmlAddressDecoder::getInstance().amount["column"]) { return false; } - if (decodedAddress.row >= xmlAddressDecoder::getInstance().amount["row"]) { + if (decodedAddress.row >= XmlAddressDecoder::getInstance().amount["row"]) { return false; } return true; diff --git a/DRAMSys/library/src/simulation/SimpleArbiter.h b/DRAMSys/library/src/simulation/SimpleArbiter.h index ec1994ae..ed2f01b5 100644 --- a/DRAMSys/library/src/simulation/SimpleArbiter.h +++ b/DRAMSys/library/src/simulation/SimpleArbiter.h @@ -38,7 +38,7 @@ #define SIMPLEARBITER_H #include "IArbiter.h" -#include "../common/xmlAddressdecoder.h" +#include "../common/rename_XmlAddressDecoder.h" #include "../common/dramExtension.h" #include "../controller/core/TimingCalculation.h" diff --git a/DRAMSys/library/src/simulation/StlPlayer.h b/DRAMSys/library/src/simulation/StlPlayer.h index ee5ac0a0..9b7de8a9 100644 --- a/DRAMSys/library/src/simulation/StlPlayer.h +++ b/DRAMSys/library/src/simulation/StlPlayer.h @@ -40,7 +40,7 @@ #ifndef STLPLAYER_H #define STLPLAYER_H -#include "../common/xmlAddressdecoder.h" +#include "../common/rename_XmlAddressDecoder.h" #include "TracePlayer.h" using namespace std; diff --git a/DRAMSys/library/src/simulation/TracePlayer.h b/DRAMSys/library/src/simulation/TracePlayer.h index dd4cb8ae..f73516b3 100644 --- a/DRAMSys/library/src/simulation/TracePlayer.h +++ b/DRAMSys/library/src/simulation/TracePlayer.h @@ -49,7 +49,7 @@ #include "MemoryManager.h" #include "../controller/core/configuration/Configuration.h" #include "../common/DebugManager.h" -#include "../common/xmlAddressdecoder.h" +#include "../common/rename_XmlAddressDecoder.h" #include "../controller/core/TimingCalculation.h" #include "TracePlayerListener.h" From 761bd8946f2d55375cb181fc52c11121a27f9ca5 Mon Sep 17 00:00:00 2001 From: Lukas Steiner Date: Wed, 12 Jun 2019 16:22:45 +0200 Subject: [PATCH 78/97] Renaming files (Commit 2 of 2) --- DRAMSys/library/library.pro | 8 ++++---- DRAMSys/library/src/common/AddressDecoder.cpp | 4 ++-- ..._CongenAddressDecoder.cpp => CongenAddressDecoder.cpp} | 2 +- ...name_CongenAddressDecoder.h => CongenAddressDecoder.h} | 0 DRAMSys/library/src/common/TlmRecorder.cpp | 2 +- DRAMSys/library/src/common/TlmRecorder.h | 2 +- ...rename_XmlAddressDecoder.cpp => XmlAddressDecoder.cpp} | 2 +- .../{rename_XmlAddressDecoder.h => XmlAddressDecoder.h} | 0 .../src/controller/core/configuration/Configuration.cpp | 2 +- DRAMSys/library/src/error/eccbaseclass.h | 2 +- DRAMSys/library/src/error/errormodel.h | 2 +- DRAMSys/library/src/simulation/Arbiter.h | 2 +- DRAMSys/library/src/simulation/DRAMSys.cpp | 4 ++-- DRAMSys/library/src/simulation/SimpleArbiter.h | 2 +- DRAMSys/library/src/simulation/StlPlayer.h | 2 +- DRAMSys/library/src/simulation/TracePlayer.h | 2 +- 16 files changed, 19 insertions(+), 19 deletions(-) rename DRAMSys/library/src/common/{rename_CongenAddressDecoder.cpp => CongenAddressDecoder.cpp} (99%) rename DRAMSys/library/src/common/{rename_CongenAddressDecoder.h => CongenAddressDecoder.h} (100%) rename DRAMSys/library/src/common/{rename_XmlAddressDecoder.cpp => XmlAddressDecoder.cpp} (99%) rename DRAMSys/library/src/common/{rename_XmlAddressDecoder.h => XmlAddressDecoder.h} (100%) diff --git a/DRAMSys/library/library.pro b/DRAMSys/library/library.pro index 6ea08e13..b1ab01a0 100644 --- a/DRAMSys/library/library.pro +++ b/DRAMSys/library/library.pro @@ -142,8 +142,8 @@ SOURCES += \ src/simulation/Dram.cpp \ src/simulation/RecordableDram.cpp \ src/simulation/Arbiter.cpp \ - src/common/rename_CongenAddressDecoder.cpp \ - src/common/rename_XmlAddressDecoder.cpp + src/common/CongenAddressDecoder.cpp \ + src/common/XmlAddressDecoder.cpp HEADERS += \ src/common/third_party/tinyxml2/tinyxml2.h \ @@ -220,8 +220,8 @@ HEADERS += \ src/controller/RecordableController.h \ src/simulation/RecordableDram.h \ src/common/AddressDecoder.h \ - src/common/rename_CongenAddressDecoder.h \ - src/common/rename_XmlAddressDecoder.h + src/common/CongenAddressDecoder.h \ + src/common/XmlAddressDecoder.h #src/common/third_party/json/include/nlohmann/json.hpp \ thermalsim = $$(THERMALSIM) diff --git a/DRAMSys/library/src/common/AddressDecoder.cpp b/DRAMSys/library/src/common/AddressDecoder.cpp index ee6b4b38..b0a3b98f 100644 --- a/DRAMSys/library/src/common/AddressDecoder.cpp +++ b/DRAMSys/library/src/common/AddressDecoder.cpp @@ -34,8 +34,8 @@ */ #include "AddressDecoder.h" -#include "rename_XmlAddressDecoder.h" -#include "rename_CongenAddressDecoder.h" +#include "XmlAddressDecoder.h" +#include "CongenAddressDecoder.h" AddressDecoder *AddressDecoder::m_pInstance = nullptr; diff --git a/DRAMSys/library/src/common/rename_CongenAddressDecoder.cpp b/DRAMSys/library/src/common/CongenAddressDecoder.cpp similarity index 99% rename from DRAMSys/library/src/common/rename_CongenAddressDecoder.cpp rename to DRAMSys/library/src/common/CongenAddressDecoder.cpp index 071967f8..6d71e39b 100644 --- a/DRAMSys/library/src/common/rename_CongenAddressDecoder.cpp +++ b/DRAMSys/library/src/common/CongenAddressDecoder.cpp @@ -33,7 +33,7 @@ * Johannes Feldmann */ -#include "rename_CongenAddressDecoder.h" +#include "CongenAddressDecoder.h" #include "Utils.h" #include diff --git a/DRAMSys/library/src/common/rename_CongenAddressDecoder.h b/DRAMSys/library/src/common/CongenAddressDecoder.h similarity index 100% rename from DRAMSys/library/src/common/rename_CongenAddressDecoder.h rename to DRAMSys/library/src/common/CongenAddressDecoder.h diff --git a/DRAMSys/library/src/common/TlmRecorder.cpp b/DRAMSys/library/src/common/TlmRecorder.cpp index 3709a487..f32ec20f 100644 --- a/DRAMSys/library/src/common/TlmRecorder.cpp +++ b/DRAMSys/library/src/common/TlmRecorder.cpp @@ -42,7 +42,7 @@ #include "TlmRecorder.h" #include "protocol.h" #include "dramExtension.h" -#include "rename_XmlAddressDecoder.h" +#include "XmlAddressDecoder.h" #include "../controller/core/configuration/Configuration.h" #include "../controller/Controller.h" diff --git a/DRAMSys/library/src/common/TlmRecorder.h b/DRAMSys/library/src/common/TlmRecorder.h index 150e0c3b..f6b97c91 100644 --- a/DRAMSys/library/src/common/TlmRecorder.h +++ b/DRAMSys/library/src/common/TlmRecorder.h @@ -49,7 +49,7 @@ #include #include #include -#include "rename_XmlAddressDecoder.h" +#include "XmlAddressDecoder.h" #include "DebugManager.h" #include "Utils.h" diff --git a/DRAMSys/library/src/common/rename_XmlAddressDecoder.cpp b/DRAMSys/library/src/common/XmlAddressDecoder.cpp similarity index 99% rename from DRAMSys/library/src/common/rename_XmlAddressDecoder.cpp rename to DRAMSys/library/src/common/XmlAddressDecoder.cpp index 403ac560..1f487f65 100644 --- a/DRAMSys/library/src/common/rename_XmlAddressDecoder.cpp +++ b/DRAMSys/library/src/common/XmlAddressDecoder.cpp @@ -35,7 +35,7 @@ * Matthias Jung */ -#include "rename_XmlAddressDecoder.h" +#include "XmlAddressDecoder.h" #include #include "Utils.h" #include "bitset" diff --git a/DRAMSys/library/src/common/rename_XmlAddressDecoder.h b/DRAMSys/library/src/common/XmlAddressDecoder.h similarity index 100% rename from DRAMSys/library/src/common/rename_XmlAddressDecoder.h rename to DRAMSys/library/src/common/XmlAddressDecoder.h diff --git a/DRAMSys/library/src/controller/core/configuration/Configuration.cpp b/DRAMSys/library/src/controller/core/configuration/Configuration.cpp index fa69feae..52904001 100644 --- a/DRAMSys/library/src/controller/core/configuration/Configuration.cpp +++ b/DRAMSys/library/src/controller/core/configuration/Configuration.cpp @@ -40,7 +40,7 @@ #include "Configuration.h" #include "ConfigurationLoader.h" -#include "../../../common/rename_XmlAddressDecoder.h" +#include "../../../common/XmlAddressDecoder.h" using namespace std; diff --git a/DRAMSys/library/src/error/eccbaseclass.h b/DRAMSys/library/src/error/eccbaseclass.h index 4219d8c3..720be2d7 100644 --- a/DRAMSys/library/src/error/eccbaseclass.h +++ b/DRAMSys/library/src/error/eccbaseclass.h @@ -8,7 +8,7 @@ #include "ECC/ECC.h" -#include "../common/rename_XmlAddressDecoder.h" +#include "../common/XmlAddressDecoder.h" #include "../common/DebugManager.h" using namespace std; diff --git a/DRAMSys/library/src/error/errormodel.h b/DRAMSys/library/src/error/errormodel.h index 5f942b14..e562401c 100644 --- a/DRAMSys/library/src/error/errormodel.h +++ b/DRAMSys/library/src/error/errormodel.h @@ -40,7 +40,7 @@ #include #include #include "../controller/core/configuration/Configuration.h" -#include "../common/rename_XmlAddressDecoder.h" +#include "../common/XmlAddressDecoder.h" #include "../common/third_party/DRAMPower/src/libdrampower/LibDRAMPower.h" class errorModel : public sc_module diff --git a/DRAMSys/library/src/simulation/Arbiter.h b/DRAMSys/library/src/simulation/Arbiter.h index feeedec3..86d1d1c9 100644 --- a/DRAMSys/library/src/simulation/Arbiter.h +++ b/DRAMSys/library/src/simulation/Arbiter.h @@ -46,7 +46,7 @@ #include #include #include -#include "../common/rename_XmlAddressDecoder.h" +#include "../common/XmlAddressDecoder.h" #include "../common/dramExtension.h" #include "../controller/core/TimingCalculation.h" #include "../controller/core/configuration/ConfigurationLoader.h" diff --git a/DRAMSys/library/src/simulation/DRAMSys.cpp b/DRAMSys/library/src/simulation/DRAMSys.cpp index dc798194..1e3e5d1b 100644 --- a/DRAMSys/library/src/simulation/DRAMSys.cpp +++ b/DRAMSys/library/src/simulation/DRAMSys.cpp @@ -46,8 +46,8 @@ #include "Setup.h" #include "../common/TlmRecorder.h" #include "../common/DebugManager.h" -#include "../common/rename_XmlAddressDecoder.h" -#include "../common/rename_CongenAddressDecoder.h" +#include "../common/XmlAddressDecoder.h" +#include "../common/CongenAddressDecoder.h" #include "../controller/core/ControllerCore.h" #include "../controller/core/configuration/ConfigurationLoader.h" #include "../common/Utils.h" diff --git a/DRAMSys/library/src/simulation/SimpleArbiter.h b/DRAMSys/library/src/simulation/SimpleArbiter.h index ed2f01b5..bc2f7b9e 100644 --- a/DRAMSys/library/src/simulation/SimpleArbiter.h +++ b/DRAMSys/library/src/simulation/SimpleArbiter.h @@ -38,7 +38,7 @@ #define SIMPLEARBITER_H #include "IArbiter.h" -#include "../common/rename_XmlAddressDecoder.h" +#include "../common/XmlAddressDecoder.h" #include "../common/dramExtension.h" #include "../controller/core/TimingCalculation.h" diff --git a/DRAMSys/library/src/simulation/StlPlayer.h b/DRAMSys/library/src/simulation/StlPlayer.h index 9b7de8a9..b8b0e9a8 100644 --- a/DRAMSys/library/src/simulation/StlPlayer.h +++ b/DRAMSys/library/src/simulation/StlPlayer.h @@ -40,7 +40,7 @@ #ifndef STLPLAYER_H #define STLPLAYER_H -#include "../common/rename_XmlAddressDecoder.h" +#include "../common/XmlAddressDecoder.h" #include "TracePlayer.h" using namespace std; diff --git a/DRAMSys/library/src/simulation/TracePlayer.h b/DRAMSys/library/src/simulation/TracePlayer.h index f73516b3..5adbd09e 100644 --- a/DRAMSys/library/src/simulation/TracePlayer.h +++ b/DRAMSys/library/src/simulation/TracePlayer.h @@ -49,7 +49,7 @@ #include "MemoryManager.h" #include "../controller/core/configuration/Configuration.h" #include "../common/DebugManager.h" -#include "../common/rename_XmlAddressDecoder.h" +#include "../common/XmlAddressDecoder.h" #include "../controller/core/TimingCalculation.h" #include "TracePlayerListener.h" From cd67d638d43f4388c0facbaea48af84244e7156c Mon Sep 17 00:00:00 2001 From: Lukas Steiner Date: Wed, 12 Jun 2019 19:28:31 +0200 Subject: [PATCH 79/97] Renaming files (Commit 1 of 2) --- DRAMSys/library/library.pro | 16 ++++++++-------- .../library/src/common/CongenAddressDecoder.cpp | 2 +- DRAMSys/library/src/common/DebugManager.h | 8 ++++---- DRAMSys/library/src/common/TlmRecorder.cpp | 2 +- DRAMSys/library/src/common/TlmRecorder.h | 8 ++++---- DRAMSys/library/src/common/XmlAddressDecoder.cpp | 2 +- DRAMSys/library/src/common/XmlAddressDecoder.h | 8 ++++---- .../{dramExtension.cpp => dramExtensions.cpp} | 4 ++-- .../common/{dramExtension.h => dramExtensions.h} | 6 +++--- DRAMSys/library/src/common/protocol.h | 6 +++--- .../src/common/{Utils.cpp => rename_utils.cpp} | 4 ++-- .../src/common/{Utils.h => rename_utils.h} | 8 ++++---- DRAMSys/library/src/controller/Command.h | 6 +++--- DRAMSys/library/src/controller/Controller.h | 12 ++++++------ .../library/src/controller/ControllerState.cpp | 2 +- DRAMSys/library/src/controller/ControllerState.h | 6 +++--- DRAMSys/library/src/controller/IController.h | 2 +- .../library/src/controller/RowBufferStates.cpp | 2 +- DRAMSys/library/src/controller/RowBufferStates.h | 8 ++++---- .../src/controller/core/ControllerCore.cpp | 6 +++--- .../library/src/controller/core/ControllerCore.h | 6 +++--- DRAMSys/library/src/controller/core/Slots.cpp | 2 +- DRAMSys/library/src/controller/core/Slots.h | 8 ++++---- .../core/configuration/Configuration.h | 8 ++++---- .../core/configuration/ConfigurationLoader.cpp | 2 +- .../core/configuration/ConfigurationLoader.h | 8 ++++---- .../src/controller/core/configuration/MemSpec.h | 2 +- .../core/configuration/thermalSimConfig.h | 2 +- .../core/powerdown/IPowerDownManager.h | 8 ++++---- .../src/controller/core/powerdown/NoPowerDown.h | 2 +- .../core/powerdown/PowerDownManager.cpp | 4 ++-- .../controller/core/powerdown/PowerDownManager.h | 6 +++--- .../core/powerdown/PowerDownManagerBankwise.cpp | 4 ++-- .../core/powerdown/PowerDownManagerBankwise.h | 8 ++++---- .../core/powerdown/PowerDownManagerTimeout.cpp | 4 ++-- .../core/powerdown/PowerDownManagerTimeout.h | 8 ++++---- .../PowerDownManagerTimeoutBankwise.cpp | 4 ++-- .../powerdown/PowerDownManagerTimeoutBankwise.h | 8 ++++---- .../controller/core/refresh/IRefreshManager.h | 6 +++--- .../library/src/controller/core/refresh/RGR.cpp | 4 ++-- .../library/src/controller/core/refresh/RGR.h | 12 ++++++++---- .../controller/core/refresh/RefreshManager.cpp | 4 ++-- .../src/controller/core/refresh/RefreshManager.h | 6 +++--- .../core/refresh/RefreshManagerBankwise.cpp | 4 ++-- .../core/refresh/RefreshManagerBankwise.h | 6 +++--- .../core/scheduling/ScheduledCommand.cpp | 4 ++-- .../core/scheduling/ScheduledCommand.h | 10 +++++----- .../src/controller/core/scheduling/Trigger.h | 6 +++--- .../core/scheduling/checker/ActBChecker.cpp | 4 ++-- .../core/scheduling/checker/ActBChecker.h | 7 ++++--- .../core/scheduling/checker/ActivateChecker.cpp | 4 ++-- .../core/scheduling/checker/ActivateChecker.h | 6 +++--- .../core/scheduling/checker/ICommandChecker.h | 6 +++--- .../core/scheduling/checker/PowerDownChecker.cpp | 2 +- .../core/scheduling/checker/PowerDownChecker.h | 6 +++--- .../core/scheduling/checker/PreBChecker.cpp | 2 +- .../core/scheduling/checker/PreBChecker.h | 10 +++++++--- .../scheduling/checker/PrechargeAllChecker.cpp | 2 +- .../scheduling/checker/PrechargeAllChecker.h | 7 +++---- .../core/scheduling/checker/PrechargeChecker.cpp | 2 +- .../core/scheduling/checker/PrechargeChecker.h | 7 +++---- .../core/scheduling/checker/ReadChecker.cpp | 4 ++-- .../core/scheduling/checker/ReadChecker.h | 6 +++--- .../core/scheduling/checker/RefreshChecker.cpp | 2 +- .../core/scheduling/checker/RefreshChecker.h | 7 +++---- .../core/scheduling/checker/WriteChecker.cpp | 4 ++-- .../core/scheduling/checker/WriteChecker.h | 7 +++---- ...ingCalculation.cpp => timingCalculations.cpp} | 4 ++-- ...{TimingCalculation.h => timingCalculations.h} | 8 ++++---- DRAMSys/library/src/controller/scheduler/Fifo.h | 6 +++--- .../src/controller/scheduler/FifoStrict.h | 2 +- .../library/src/controller/scheduler/FrFcfs.cpp | 2 +- .../library/src/controller/scheduler/FrFcfs.h | 6 +++--- .../src/controller/scheduler/IScheduler.h | 2 +- DRAMSys/library/src/controller/scheduler/SMS.h | 2 +- DRAMSys/library/src/simulation/Arbiter.h | 10 +++++----- DRAMSys/library/src/simulation/DRAMSys.cpp | 2 +- DRAMSys/library/src/simulation/DRAMSys.h | 6 +++--- DRAMSys/library/src/simulation/Dram.cpp | 6 +++--- DRAMSys/library/src/simulation/Dram.h | 6 +++--- .../library/src/simulation/ExampleInitiator.h | 8 ++++---- DRAMSys/library/src/simulation/IArbiter.h | 6 +++--- DRAMSys/library/src/simulation/MemoryManager.h | 6 +++--- DRAMSys/library/src/simulation/RecordableDram.h | 6 +++--- DRAMSys/library/src/simulation/Setup.h | 2 +- DRAMSys/library/src/simulation/SimpleArbiter.h | 4 ++-- .../src/simulation/TemperatureController.h | 8 ++++---- DRAMSys/library/src/simulation/TraceGenerator.h | 2 +- DRAMSys/library/src/simulation/TracePlayer.h | 8 ++++---- DRAMSys/library/src/simulation/TraceSetup.h | 2 +- 90 files changed, 244 insertions(+), 239 deletions(-) rename DRAMSys/library/src/common/{dramExtension.cpp => dramExtensions.cpp} (99%) rename DRAMSys/library/src/common/{dramExtension.h => dramExtensions.h} (98%) rename DRAMSys/library/src/common/{Utils.cpp => rename_utils.cpp} (99%) rename DRAMSys/library/src/common/{Utils.h => rename_utils.h} (97%) rename DRAMSys/library/src/controller/core/{TimingCalculation.cpp => timingCalculations.cpp} (98%) rename DRAMSys/library/src/controller/core/{TimingCalculation.h => timingCalculations.h} (94%) diff --git a/DRAMSys/library/library.pro b/DRAMSys/library/library.pro index b1ab01a0..2c4050f5 100644 --- a/DRAMSys/library/library.pro +++ b/DRAMSys/library/library.pro @@ -86,9 +86,7 @@ QMAKE_CXXFLAGS += -isystem $${systemc_home}/include SOURCES += \ src/common/third_party/tinyxml2/tinyxml2.cpp \ - src/common/Utils.cpp \ src/common/TlmRecorder.cpp \ - src/common/dramExtension.cpp \ src/common/DebugManager.cpp \ src/controller/core/configuration/Configuration.cpp \ src/controller/core/powerdown/PowerDownManagerTimeout.cpp \ @@ -110,7 +108,6 @@ SOURCES += \ src/controller/core/scheduling/checker/PreBChecker.cpp \ src/controller/core/scheduling/checker/ActBChecker.cpp \ src/controller/core/scheduling/ScheduledCommand.cpp \ - src/controller/core/TimingCalculation.cpp \ src/controller/core/Slots.cpp \ src/controller/core/ControllerCore.cpp \ src/simulation/MemoryManager.cpp \ @@ -143,15 +140,16 @@ SOURCES += \ src/simulation/RecordableDram.cpp \ src/simulation/Arbiter.cpp \ src/common/CongenAddressDecoder.cpp \ - src/common/XmlAddressDecoder.cpp + src/common/XmlAddressDecoder.cpp \ + src/common/rename_utils.cpp \ + src/controller/core/timingCalculations.cpp \ + src/common/dramExtensions.cpp HEADERS += \ src/common/third_party/tinyxml2/tinyxml2.h \ - src/common/Utils.h \ src/common/TlmRecorder.h \ src/common/tlm2_base_protocol_checker.h \ src/common/protocol.h \ - src/common/dramExtension.h \ src/common/DebugManager.h \ src/controller/core/configuration/Configuration.h \ src/controller/core/powerdown/PowerDownManagerTimeout.h \ @@ -177,7 +175,6 @@ HEADERS += \ src/controller/core/scheduling/checker/ActBChecker.h \ src/controller/core/scheduling/Trigger.h \ src/controller/core/scheduling/ScheduledCommand.h \ - src/controller/core/TimingCalculation.h \ src/controller/core/Slots.h \ src/controller/core/ControllerCore.h \ src/simulation/TracePlayer.h \ @@ -221,7 +218,10 @@ HEADERS += \ src/simulation/RecordableDram.h \ src/common/AddressDecoder.h \ src/common/CongenAddressDecoder.h \ - src/common/XmlAddressDecoder.h + src/common/XmlAddressDecoder.h \ + src/common/rename_utils.h \ + src/controller/core/timingCalculations.h \ + src/common/dramExtensions.h #src/common/third_party/json/include/nlohmann/json.hpp \ thermalsim = $$(THERMALSIM) diff --git a/DRAMSys/library/src/common/CongenAddressDecoder.cpp b/DRAMSys/library/src/common/CongenAddressDecoder.cpp index 6d71e39b..8ca2ce74 100644 --- a/DRAMSys/library/src/common/CongenAddressDecoder.cpp +++ b/DRAMSys/library/src/common/CongenAddressDecoder.cpp @@ -34,7 +34,7 @@ */ #include "CongenAddressDecoder.h" -#include "Utils.h" +#include "rename_utils.h" #include diff --git a/DRAMSys/library/src/common/DebugManager.h b/DRAMSys/library/src/common/DebugManager.h index be40527b..f3810dee 100644 --- a/DRAMSys/library/src/common/DebugManager.h +++ b/DRAMSys/library/src/common/DebugManager.h @@ -34,13 +34,13 @@ * Matthias Jung */ -#ifndef DEBUGMANAGER_H_ -#define DEBUGMANAGER_H_ +#ifndef DEBUGMANAGER_H +#define DEBUGMANAGER_H #include #include #include -#include "Utils.h" +#include "rename_utils.h" class DebugManager { @@ -63,4 +63,4 @@ private: ofstream debugFile; }; -#endif /* DEBUGMANAGER_H_ */ +#endif // DEBUGMANAGER_H diff --git a/DRAMSys/library/src/common/TlmRecorder.cpp b/DRAMSys/library/src/common/TlmRecorder.cpp index f32ec20f..c365c060 100644 --- a/DRAMSys/library/src/common/TlmRecorder.cpp +++ b/DRAMSys/library/src/common/TlmRecorder.cpp @@ -41,7 +41,7 @@ #include "TlmRecorder.h" #include "protocol.h" -#include "dramExtension.h" +#include "dramExtensions.h" #include "XmlAddressDecoder.h" #include "../controller/core/configuration/Configuration.h" #include "../controller/Controller.h" diff --git a/DRAMSys/library/src/common/TlmRecorder.h b/DRAMSys/library/src/common/TlmRecorder.h index f6b97c91..8b8ef016 100644 --- a/DRAMSys/library/src/common/TlmRecorder.h +++ b/DRAMSys/library/src/common/TlmRecorder.h @@ -36,8 +36,8 @@ * Eder F. Zulian */ -#ifndef TLMPHASERECORDER_H -#define TLMPHASERECORDER_H +#ifndef TLMRECORDER_H +#define TLMRECORDER_H #include #include @@ -51,7 +51,7 @@ #include #include "XmlAddressDecoder.h" #include "DebugManager.h" -#include "Utils.h" +#include "rename_utils.h" using namespace std; @@ -150,5 +150,5 @@ private: insertDebugMessageString, updateDataStrobeString, insertPowerString; }; -#endif +#endif // TLMRECORDER_H diff --git a/DRAMSys/library/src/common/XmlAddressDecoder.cpp b/DRAMSys/library/src/common/XmlAddressDecoder.cpp index 1f487f65..caa49062 100644 --- a/DRAMSys/library/src/common/XmlAddressDecoder.cpp +++ b/DRAMSys/library/src/common/XmlAddressDecoder.cpp @@ -37,7 +37,7 @@ #include "XmlAddressDecoder.h" #include -#include "Utils.h" +#include "rename_utils.h" #include "bitset" #include "../controller/core/configuration/Configuration.h" diff --git a/DRAMSys/library/src/common/XmlAddressDecoder.h b/DRAMSys/library/src/common/XmlAddressDecoder.h index 6f87bcd5..488eb4a7 100644 --- a/DRAMSys/library/src/common/XmlAddressDecoder.h +++ b/DRAMSys/library/src/common/XmlAddressDecoder.h @@ -35,12 +35,12 @@ * Matthias Jung */ -#ifndef _XMLADDRESSDECODER_H -#define _XMLADDRESSDECODER_H +#ifndef XMLADDRESSDECODER_H +#define XMLADDRESSDECODER_H #include -#include "Utils.h" +#include "rename_utils.h" #include "third_party/tinyxml2/tinyxml2.h" #include "AddressDecoder.h" @@ -71,4 +71,4 @@ public: virtual void print(); }; -#endif +#endif // XMLADDRESSDECODER_H diff --git a/DRAMSys/library/src/common/dramExtension.cpp b/DRAMSys/library/src/common/dramExtensions.cpp similarity index 99% rename from DRAMSys/library/src/common/dramExtension.cpp rename to DRAMSys/library/src/common/dramExtensions.cpp index bfb7b7c4..51ee8578 100644 --- a/DRAMSys/library/src/common/dramExtension.cpp +++ b/DRAMSys/library/src/common/dramExtensions.cpp @@ -35,10 +35,10 @@ * Matthias Jung */ -#include "dramExtension.h" +#include "dramExtensions.h" #include "../controller/core/configuration/Configuration.h" #include "map" -#include "Utils.h" +#include "rename_utils.h" using namespace tlm; diff --git a/DRAMSys/library/src/common/dramExtension.h b/DRAMSys/library/src/common/dramExtensions.h similarity index 98% rename from DRAMSys/library/src/common/dramExtension.h rename to DRAMSys/library/src/common/dramExtensions.h index c990e912..2f62ab94 100644 --- a/DRAMSys/library/src/common/dramExtension.h +++ b/DRAMSys/library/src/common/dramExtensions.h @@ -34,8 +34,8 @@ * Matthias Jung */ -#ifndef DRAMEXTENSION_H_ -#define DRAMEXTENSION_H_ +#ifndef DRAMEXTENSIONS_H +#define DRAMEXTENSIONS_H #include #include @@ -238,4 +238,4 @@ bool operator!=(const Row &lhs, const Row &rhs); bool operator==(const Column &lhs, const Column &rhs); bool operator!=(const Column &lhs, const Column &rhs); -#endif /* DRAMEXTENSION_H_ */ +#endif // DRAMEXTENSIONS_H diff --git a/DRAMSys/library/src/common/protocol.h b/DRAMSys/library/src/common/protocol.h index 00b03c36..06af9c30 100644 --- a/DRAMSys/library/src/common/protocol.h +++ b/DRAMSys/library/src/common/protocol.h @@ -35,8 +35,8 @@ * Matthias Jung */ -#ifndef EXTENDED_PHASE_DRAM -#define EXTENDED_PHASE_DRAM +#ifndef PROTOCOL_H +#define PROTOCOL_H // DRAM Control Phases DECLARE_EXTENDED_PHASE(BEGIN_PREB); @@ -100,5 +100,5 @@ DECLARE_EXTENDED_PHASE(REF_TRIGGER); DECLARE_EXTENDED_PHASE(PDN_TRIGGER); -#endif +#endif // PROTOCOL_H diff --git a/DRAMSys/library/src/common/Utils.cpp b/DRAMSys/library/src/common/rename_utils.cpp similarity index 99% rename from DRAMSys/library/src/common/Utils.cpp rename to DRAMSys/library/src/common/rename_utils.cpp index 6634201b..9e0c19a8 100644 --- a/DRAMSys/library/src/common/Utils.cpp +++ b/DRAMSys/library/src/common/rename_utils.cpp @@ -35,11 +35,11 @@ * Matthias Jung */ -#include "Utils.h" +#include "rename_utils.h" #include #include #include -#include "dramExtension.h" +#include "dramExtensions.h" #include "../controller/Controller.h" using namespace std; diff --git a/DRAMSys/library/src/common/Utils.h b/DRAMSys/library/src/common/rename_utils.h similarity index 97% rename from DRAMSys/library/src/common/Utils.h rename to DRAMSys/library/src/common/rename_utils.h index ac7a71a1..79bf1c5b 100644 --- a/DRAMSys/library/src/common/Utils.h +++ b/DRAMSys/library/src/common/rename_utils.h @@ -35,8 +35,8 @@ * Eder F. Zulian */ -#ifndef UTILS_COMMON_UTILS_H_ -#define UTILS_COMMON_UTILS_H_ +#ifndef UTILS_H +#define UTILS_H #include #include @@ -44,7 +44,7 @@ #include #include #include -#include "dramExtension.h" +#include "dramExtensions.h" #include "third_party/tinyxml2/tinyxml2.h" #define DEF_SINGLETON( NAME ) \ @@ -148,5 +148,5 @@ double queryDoubleParameter(tinyxml2::XMLElement *node, std::string name); void setUpDummy(tlm::tlm_generic_payload &payload, Bank &bank); -#endif /* UTILS_COMMON_H_ */ +#endif // UTILS_H diff --git a/DRAMSys/library/src/controller/Command.h b/DRAMSys/library/src/controller/Command.h index da66fef4..c2b87464 100644 --- a/DRAMSys/library/src/controller/Command.h +++ b/DRAMSys/library/src/controller/Command.h @@ -33,8 +33,8 @@ * Janik Schlemminger * Matthias Jung */ -#ifndef COMMAND_H_ -#define COMMAND_H_ +#ifndef COMMAND_H +#define COMMAND_H #include #include @@ -64,4 +64,4 @@ std::string commandToString(Command command); const std::vector &getAllCommands(); bool commandIsIn(Command command, std::vector commands); -#endif /* COMMAND_H_ */ +#endif // COMMAND_H diff --git a/DRAMSys/library/src/controller/Controller.h b/DRAMSys/library/src/controller/Controller.h index 3b604c63..0a743632 100644 --- a/DRAMSys/library/src/controller/Controller.h +++ b/DRAMSys/library/src/controller/Controller.h @@ -35,8 +35,8 @@ * Eder F. Zulian */ -#ifndef CONTROLLERWRAPPER_H_ -#define CONTROLLERWRAPPER_H_ +#ifndef CONTROLLER_H +#define CONTROLLER_H #include #include @@ -49,11 +49,11 @@ #include #include -#include "../common/dramExtension.h" +#include "../common/dramExtensions.h" #include "../common/DebugManager.h" #include "../common/protocol.h" #include "../common/TlmRecorder.h" -#include "../common/Utils.h" +#include "../common/rename_utils.h" #include "core/configuration/Configuration.h" #include "core/configuration/MemSpec.h" #include "Command.h" @@ -63,7 +63,7 @@ #include "core/powerdown/IPowerDownManager.h" #include "core/scheduling/ScheduledCommand.h" #include "core/scheduling/Trigger.h" -#include "core/TimingCalculation.h" +#include "core/timingCalculations.h" #include "scheduler/Fifo.h" #include "scheduler/Grp.h" #include "scheduler/FifoStrict.h" @@ -171,5 +171,5 @@ protected: static const unsigned int controllerThreadId = INT_MAX; }; -#endif /* CONTROLLERWRAPPER_H_ */ +#endif // CONTROLLER_H diff --git a/DRAMSys/library/src/controller/ControllerState.cpp b/DRAMSys/library/src/controller/ControllerState.cpp index efff0548..a94905f8 100644 --- a/DRAMSys/library/src/controller/ControllerState.cpp +++ b/DRAMSys/library/src/controller/ControllerState.cpp @@ -37,7 +37,7 @@ #include "ControllerState.h" #include -#include "core/TimingCalculation.h" +#include "core/timingCalculations.h" using namespace std; diff --git a/DRAMSys/library/src/controller/ControllerState.h b/DRAMSys/library/src/controller/ControllerState.h index fff61882..77b99799 100644 --- a/DRAMSys/library/src/controller/ControllerState.h +++ b/DRAMSys/library/src/controller/ControllerState.h @@ -34,8 +34,8 @@ * Matthias Jung */ -#ifndef CONTROLLER_STATE_H_ -#define CONTROLLER_STATE_H_ +#ifndef CONTROLLERSTATE_H +#define CONTROLLERSTATE_H #include #include "RowBufferStates.h" @@ -84,5 +84,5 @@ private: void printDebugMessage(std::string message); }; -#endif /* CONTROLLER_STATE_H_ */ +#endif // CONTROLLERSTATE_H diff --git a/DRAMSys/library/src/controller/IController.h b/DRAMSys/library/src/controller/IController.h index ded2de7b..4504c4c3 100644 --- a/DRAMSys/library/src/controller/IController.h +++ b/DRAMSys/library/src/controller/IController.h @@ -42,7 +42,7 @@ #include #include "core/scheduling/ScheduledCommand.h" #include "core/scheduling/Trigger.h" -#include "../common/dramExtension.h" +#include "../common/dramExtensions.h" // Utiliy class to pass around the Controller class to the controller Core and various schedulers, without having to propagate the template defintions diff --git a/DRAMSys/library/src/controller/RowBufferStates.cpp b/DRAMSys/library/src/controller/RowBufferStates.cpp index 2948203a..4c57d257 100644 --- a/DRAMSys/library/src/controller/RowBufferStates.cpp +++ b/DRAMSys/library/src/controller/RowBufferStates.cpp @@ -37,7 +37,7 @@ #include "RowBufferStates.h" #include "core/ControllerCore.h" #include "../common/DebugManager.h" -#include "../common/Utils.h" +#include "../common/rename_utils.h" using namespace std; diff --git a/DRAMSys/library/src/controller/RowBufferStates.h b/DRAMSys/library/src/controller/RowBufferStates.h index 63de434e..f2670dec 100644 --- a/DRAMSys/library/src/controller/RowBufferStates.h +++ b/DRAMSys/library/src/controller/RowBufferStates.h @@ -34,11 +34,11 @@ * Matthias Jung */ -#ifndef ROWBUFFERSTATES_H_ -#define ROWBUFFERSTATES_H_ +#ifndef ROWBUFFERSTATES_H +#define ROWBUFFERSTATES_H #include -#include "../common/dramExtension.h" +#include "../common/dramExtensions.h" class RowBufferState { @@ -60,5 +60,5 @@ private: void printDebugMessage(std::string message); }; -#endif /* BANKSTATES_H_ */ +#endif // ROWBUFFERSTATES_H diff --git a/DRAMSys/library/src/controller/core/ControllerCore.cpp b/DRAMSys/library/src/controller/core/ControllerCore.cpp index ba8d1ebe..92dfe1a1 100644 --- a/DRAMSys/library/src/controller/core/ControllerCore.cpp +++ b/DRAMSys/library/src/controller/core/ControllerCore.cpp @@ -49,9 +49,9 @@ #include "refresh/RefreshManagerBankwise.h" #include "refresh/RefreshManager.h" #include "refresh/RGR.h" -#include "../../common/dramExtension.h" -#include "../../common/Utils.h" -#include "TimingCalculation.h" +#include "../../common/dramExtensions.h" +#include "../../common/rename_utils.h" +#include "timingCalculations.h" #include "powerdown/PowerDownManager.h" #include "powerdown/PowerDownManagerTimeout.h" diff --git a/DRAMSys/library/src/controller/core/ControllerCore.h b/DRAMSys/library/src/controller/core/ControllerCore.h index 7b00f1ea..f0b7dc99 100644 --- a/DRAMSys/library/src/controller/core/ControllerCore.h +++ b/DRAMSys/library/src/controller/core/ControllerCore.h @@ -34,8 +34,8 @@ * Matthias Jung */ -#ifndef CONTROLLER_H_ -#define CONTROLLER_H_ +#ifndef CONTROLLERCORE_H +#define CONTROLLERCORE_H #include #include @@ -88,5 +88,5 @@ private: void printDebugMessage(string message); }; -#endif /* CONTROLLER_H_ */ +#endif // CONTROLLERCORE_H diff --git a/DRAMSys/library/src/controller/core/Slots.cpp b/DRAMSys/library/src/controller/core/Slots.cpp index 20126eab..d74ce9e9 100644 --- a/DRAMSys/library/src/controller/core/Slots.cpp +++ b/DRAMSys/library/src/controller/core/Slots.cpp @@ -35,7 +35,7 @@ */ #include "Slots.h" -#include "TimingCalculation.h" +#include "timingCalculations.h" Slots::Slots(sc_time clk) : diff --git a/DRAMSys/library/src/controller/core/Slots.h b/DRAMSys/library/src/controller/core/Slots.h index 5a821a4b..61663568 100644 --- a/DRAMSys/library/src/controller/core/Slots.h +++ b/DRAMSys/library/src/controller/core/Slots.h @@ -34,13 +34,13 @@ * Matthias Jung */ -#ifndef SLOTS_H_ -#define SLOTS_H_ +#ifndef SLOTS_H +#define SLOTS_H + #include #include #include "scheduling/ScheduledCommand.h" - class Slots { public: @@ -60,4 +60,4 @@ private: }; -#endif /* SLOTS_H_ */ +#endif // SLOTS_H diff --git a/DRAMSys/library/src/controller/core/configuration/Configuration.h b/DRAMSys/library/src/controller/core/configuration/Configuration.h index 37b7f4ea..6472a4c5 100644 --- a/DRAMSys/library/src/controller/core/configuration/Configuration.h +++ b/DRAMSys/library/src/controller/core/configuration/Configuration.h @@ -36,15 +36,15 @@ * Felipe S. Prado */ -#ifndef CONFIGURATION_H_ -#define CONFIGURATION_H_ +#ifndef CONFIGURATION_H +#define CONFIGURATION_H #include #include #include #include "MemSpec.h" #include "thermalSimConfig.h" -#include "../../../common/Utils.h" +#include "../../../common/rename_utils.h" #include "../../../error/eccbaseclass.h" @@ -164,5 +164,5 @@ private: unsigned int powerDownTimeoutInClk = 3; }; -#endif /* CONFIGURATION_H_ */ +#endif // CONFIGURATION_H diff --git a/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.cpp b/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.cpp index 31f478b7..a8fb37c8 100644 --- a/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.cpp +++ b/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.cpp @@ -36,7 +36,7 @@ #include "ConfigurationLoader.h" #include "MemSpec.h" -#include "../TimingCalculation.h" +#include "../timingCalculations.h" using namespace tinyxml2; using namespace std; diff --git a/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.h b/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.h index 8334cb4e..fe701b59 100644 --- a/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.h +++ b/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.h @@ -34,12 +34,12 @@ * Matthias Jung */ -#ifndef CONFIGURATIONLOADER_H_ -#define CONFIGURATIONLOADER_H_ +#ifndef CONFIGURATIONLOADER_H +#define CONFIGURATIONLOADER_H #include #include "../../../common/third_party/tinyxml2/tinyxml2.h" -#include "../../../common/Utils.h" +#include "../../../common/rename_utils.h" #include "Configuration.h" class ConfigurationLoader @@ -74,4 +74,4 @@ private: }; -#endif /* CONFIGURATIONLOADER_H_ */ +#endif // CONFIGURATIONLOADER_H diff --git a/DRAMSys/library/src/controller/core/configuration/MemSpec.h b/DRAMSys/library/src/controller/core/configuration/MemSpec.h index 434cb508..79b10329 100644 --- a/DRAMSys/library/src/controller/core/configuration/MemSpec.h +++ b/DRAMSys/library/src/controller/core/configuration/MemSpec.h @@ -39,7 +39,7 @@ #include #include -#include "../../../common/dramExtension.h" +#include "../../../common/dramExtensions.h" struct RefreshTiming { diff --git a/DRAMSys/library/src/controller/core/configuration/thermalSimConfig.h b/DRAMSys/library/src/controller/core/configuration/thermalSimConfig.h index 6d202dbc..8d13a77d 100644 --- a/DRAMSys/library/src/controller/core/configuration/thermalSimConfig.h +++ b/DRAMSys/library/src/controller/core/configuration/thermalSimConfig.h @@ -43,7 +43,7 @@ #include "../../../common/DebugManager.h" #include "../../../common/third_party/tinyxml2/tinyxml2.h" -#include "../../../common/Utils.h" +#include "../../../common/rename_utils.h" struct TemperatureSimConfig { diff --git a/DRAMSys/library/src/controller/core/powerdown/IPowerDownManager.h b/DRAMSys/library/src/controller/core/powerdown/IPowerDownManager.h index 1de77427..9ff8bd39 100644 --- a/DRAMSys/library/src/controller/core/powerdown/IPowerDownManager.h +++ b/DRAMSys/library/src/controller/core/powerdown/IPowerDownManager.h @@ -34,11 +34,11 @@ * Matthias Jung */ -#ifndef IPOWERDOWNMANAGER_H_ -#define IPOWERDOWNMANAGER_H_ +#ifndef IPOWERDOWNMANAGER_H +#define IPOWERDOWNMANAGER_H #include -#include "../../../common/dramExtension.h" +#include "../../../common/dramExtensions.h" #include "../../Command.h" @@ -126,4 +126,4 @@ inline std::string powerDownStateToString(PowerDownState powerDownState) } -#endif /* IPOWERDOWNMANAGER_H_ */ +#endif // IPOWERDOWNMANAGER_H diff --git a/DRAMSys/library/src/controller/core/powerdown/NoPowerDown.h b/DRAMSys/library/src/controller/core/powerdown/NoPowerDown.h index 13b9db16..e68d344a 100644 --- a/DRAMSys/library/src/controller/core/powerdown/NoPowerDown.h +++ b/DRAMSys/library/src/controller/core/powerdown/NoPowerDown.h @@ -40,7 +40,7 @@ #include "PowerDownManager.h" #include -#include "../../../common/dramExtension.h" +#include "../../../common/dramExtensions.h" #include "../scheduling/ScheduledCommand.h" diff --git a/DRAMSys/library/src/controller/core/powerdown/PowerDownManager.cpp b/DRAMSys/library/src/controller/core/powerdown/PowerDownManager.cpp index 93cab1a6..9d3a5258 100644 --- a/DRAMSys/library/src/controller/core/powerdown/PowerDownManager.cpp +++ b/DRAMSys/library/src/controller/core/powerdown/PowerDownManager.cpp @@ -39,10 +39,10 @@ #include #include "PowerDownManager.h" #include "../ControllerCore.h" -#include "../TimingCalculation.h" +#include "../timingCalculations.h" #include "../../../common/DebugManager.h" #include -#include "../../../common/Utils.h" +#include "../../../common/rename_utils.h" using namespace tlm; using namespace std; diff --git a/DRAMSys/library/src/controller/core/powerdown/PowerDownManager.h b/DRAMSys/library/src/controller/core/powerdown/PowerDownManager.h index a8a77e20..ee90629e 100644 --- a/DRAMSys/library/src/controller/core/powerdown/PowerDownManager.h +++ b/DRAMSys/library/src/controller/core/powerdown/PowerDownManager.h @@ -34,8 +34,8 @@ * Matthias Jung */ -#ifndef POWERDOWNMANAGER_H_ -#define POWERDOWNMANAGER_H_ +#ifndef POWERDOWNMANAGER_H +#define POWERDOWNMANAGER_H #include "PowerDownManagerBankwise.h" @@ -68,4 +68,4 @@ protected: }; -#endif /* POWERDOWNMANAGER_H_ */ +#endif // POWERDOWNMANAGER_H diff --git a/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerBankwise.cpp b/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerBankwise.cpp index 57490c88..344b1700 100644 --- a/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerBankwise.cpp +++ b/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerBankwise.cpp @@ -36,9 +36,9 @@ #include "PowerDownManager.h" #include "../ControllerCore.h" -#include "../../../common/Utils.h" +#include "../../../common/rename_utils.h" #include "../../../common/DebugManager.h" -#include "../TimingCalculation.h" +#include "../timingCalculations.h" using namespace tlm; diff --git a/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerBankwise.h b/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerBankwise.h index 5f532b00..69382538 100644 --- a/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerBankwise.h +++ b/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerBankwise.h @@ -34,15 +34,15 @@ * Matthias Jung */ -#ifndef POWERDOWNMANAGERBANKWISE_H_ -#define POWERDOWNMANAGERBANKWISE_H_ +#ifndef POWERDOWNMANAGERBANKWISE_H +#define POWERDOWNMANAGERBANKWISE_H #include #include #include #include #include "../../Command.h" -#include "../../../common/dramExtension.h" +#include "../../../common/dramExtensions.h" #include "../scheduling/ScheduledCommand.h" #include "IPowerDownManager.h" @@ -82,5 +82,5 @@ protected: void printDebugMessage(std::string message); }; -#endif /* POWERDOWNMANAGERBANKWISE_H_ */ +#endif // POWERDOWNMANAGERBANKWISE_H diff --git a/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerTimeout.cpp b/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerTimeout.cpp index c694d13f..88a97766 100644 --- a/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerTimeout.cpp +++ b/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerTimeout.cpp @@ -38,9 +38,9 @@ #include "PowerDownManagerTimeout.h" #include "../ControllerCore.h" -#include "../../../common/Utils.h" +#include "../../../common/rename_utils.h" #include "../../../common/DebugManager.h" -#include "../TimingCalculation.h" +#include "../timingCalculations.h" using namespace tlm; diff --git a/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerTimeout.h b/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerTimeout.h index 538df00c..d56675f5 100644 --- a/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerTimeout.h +++ b/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerTimeout.h @@ -36,12 +36,12 @@ * Felipe S. Prado */ -#ifndef POWERDOWNMANAGERTIMEOUT_H_ -#define POWERDOWNMANAGERTIMEOUT_H_ +#ifndef POWERDOWNMANAGERTIMEOUT_H +#define POWERDOWNMANAGERTIMEOUT_H #include "PowerDownManager.h" #include -#include "../../../common/dramExtension.h" +#include "../../../common/dramExtensions.h" #include "../scheduling/ScheduledCommand.h" #include @@ -60,4 +60,4 @@ public: -#endif /* POWERDOWNMANAGERTIMEOUT_H_ */ +#endif // POWERDOWNMANAGERTIMEOUT_H diff --git a/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerTimeoutBankwise.cpp b/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerTimeoutBankwise.cpp index 56a8b9b3..2e4a2a1a 100644 --- a/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerTimeoutBankwise.cpp +++ b/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerTimeoutBankwise.cpp @@ -38,9 +38,9 @@ #include "PowerDownManagerTimeoutBankwise.h" #include "../ControllerCore.h" -#include "../../../common/Utils.h" +#include "../../../common/rename_utils.h" #include "../../../common/DebugManager.h" -#include "../TimingCalculation.h" +#include "../timingCalculations.h" using namespace tlm; diff --git a/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerTimeoutBankwise.h b/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerTimeoutBankwise.h index 3c1fb76b..e4a43bed 100644 --- a/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerTimeoutBankwise.h +++ b/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerTimeoutBankwise.h @@ -36,12 +36,12 @@ * Felipe S. Prado */ -#ifndef POWERDOWNMANAGERTIMEOUTBANKWISE_H_ -#define POWERDOWNMANAGERTIMEOUTBANKWISE_H_ +#ifndef POWERDOWNMANAGERTIMEOUTBANKWISE_H +#define POWERDOWNMANAGERTIMEOUTBANKWISE_H #include "PowerDownManager.h" #include -#include "../../../common/dramExtension.h" +#include "../../../common/dramExtensions.h" #include "../scheduling/ScheduledCommand.h" #include @@ -60,4 +60,4 @@ public: -#endif /* POWERDOWNMANAGERTIMEOUTBANKWISE_H_ */ +#endif // POWERDOWNMANAGERTIMEOUTBANKWISE_H diff --git a/DRAMSys/library/src/controller/core/refresh/IRefreshManager.h b/DRAMSys/library/src/controller/core/refresh/IRefreshManager.h index 1668ef61..9b2f581b 100644 --- a/DRAMSys/library/src/controller/core/refresh/IRefreshManager.h +++ b/DRAMSys/library/src/controller/core/refresh/IRefreshManager.h @@ -35,8 +35,8 @@ * Matthias Jung */ -#ifndef IREFRESHMANAGER_H_ -#define IREFRESHMANAGER_H_ +#ifndef IREFRESHMANAGER_H +#define IREFRESHMANAGER_H #include #include "../scheduling/ScheduledCommand.h" @@ -62,5 +62,5 @@ public: virtual bool isInvalidated(tlm::tlm_generic_payload &payload, sc_time time) = 0; }; -#endif /* IREFRESHMANAGER_H_ */ +#endif // IREFRESHMANAGER_H diff --git a/DRAMSys/library/src/controller/core/refresh/RGR.cpp b/DRAMSys/library/src/controller/core/refresh/RGR.cpp index 37b552e4..ff4c72e5 100644 --- a/DRAMSys/library/src/controller/core/refresh/RGR.cpp +++ b/DRAMSys/library/src/controller/core/refresh/RGR.cpp @@ -36,8 +36,8 @@ #include "RGR.h" #include "../ControllerCore.h" -#include "../TimingCalculation.h" -#include "../../../common/Utils.h" +#include "../timingCalculations.h" +#include "../../../common/rename_utils.h" #define TRUE 1 #define FALSE !(TRUE) diff --git a/DRAMSys/library/src/controller/core/refresh/RGR.h b/DRAMSys/library/src/controller/core/refresh/RGR.h index 96ad8cdb..bfe8e444 100644 --- a/DRAMSys/library/src/controller/core/refresh/RGR.h +++ b/DRAMSys/library/src/controller/core/refresh/RGR.h @@ -32,12 +32,15 @@ * Author: Éder F. Zulian */ -#ifndef RGR_MANAGER_H_ -#define RGR_MANAGER_H_ -#include "../../../common/dramExtension.h" +#ifndef RGR_H +#define RGR_H + +#include "../../../common/dramExtensions.h" #include "../configuration/MemSpec.h" #include "IRefreshManager.h" + class ControllerCore; + class RGR : public IRefreshManager, public sc_module { public: @@ -73,5 +76,6 @@ private: void planNextRefresh(Bank b, sc_time t, bool align); void printDebugMessage(std::string message); }; -#endif /* RGR_MANAGER_H_ */ + +#endif // RGR_H diff --git a/DRAMSys/library/src/controller/core/refresh/RefreshManager.cpp b/DRAMSys/library/src/controller/core/refresh/RefreshManager.cpp index b07ed332..ad1cea5b 100644 --- a/DRAMSys/library/src/controller/core/refresh/RefreshManager.cpp +++ b/DRAMSys/library/src/controller/core/refresh/RefreshManager.cpp @@ -39,8 +39,8 @@ #include "RefreshManager.h" #include "../ControllerCore.h" -#include "../TimingCalculation.h" -#include "../../../common/Utils.h" +#include "../timingCalculations.h" +#include "../../../common/rename_utils.h" using namespace tlm; diff --git a/DRAMSys/library/src/controller/core/refresh/RefreshManager.h b/DRAMSys/library/src/controller/core/refresh/RefreshManager.h index c5fb5905..c89fa12b 100644 --- a/DRAMSys/library/src/controller/core/refresh/RefreshManager.h +++ b/DRAMSys/library/src/controller/core/refresh/RefreshManager.h @@ -35,8 +35,8 @@ * Éder F. Zulian */ -#ifndef REFRESHMANAGER_H_ -#define REFRESHMANAGER_H_ +#ifndef REFRESHMANAGER_H +#define REFRESHMANAGER_H #include "IRefreshManager.h" #include "../configuration/MemSpec.h" @@ -78,5 +78,5 @@ private: void printDebugMessage(std::string message); }; -#endif /* REFRESHMANAGER_H_ */ +#endif // REFRESHMANAGER_H diff --git a/DRAMSys/library/src/controller/core/refresh/RefreshManagerBankwise.cpp b/DRAMSys/library/src/controller/core/refresh/RefreshManagerBankwise.cpp index 533b7859..ab878ff0 100644 --- a/DRAMSys/library/src/controller/core/refresh/RefreshManagerBankwise.cpp +++ b/DRAMSys/library/src/controller/core/refresh/RefreshManagerBankwise.cpp @@ -37,8 +37,8 @@ #include "RefreshManagerBankwise.h" #include "../ControllerCore.h" -#include "../TimingCalculation.h" -#include "../../../common/Utils.h" +#include "../timingCalculations.h" +#include "../../../common/rename_utils.h" using namespace std; diff --git a/DRAMSys/library/src/controller/core/refresh/RefreshManagerBankwise.h b/DRAMSys/library/src/controller/core/refresh/RefreshManagerBankwise.h index 6b8558a1..1c84d83e 100644 --- a/DRAMSys/library/src/controller/core/refresh/RefreshManagerBankwise.h +++ b/DRAMSys/library/src/controller/core/refresh/RefreshManagerBankwise.h @@ -35,8 +35,8 @@ * Éder F. Zulian */ -#ifndef BANKWISEREFRESHMANAGER_H_ -#define BANKWISEREFRESHMANAGER_H_ +#ifndef BANKWISEREFRESHMANAGER_H +#define BANKWISEREFRESHMANAGER_H //#include "../../../common/dramExtension.h" #include "IRefreshManager.h" @@ -79,5 +79,5 @@ private: void printDebugMessage(std::string message); }; -#endif /* BANKWISEREFRESHMANAGER_H_ */ +#endif // BANKWISEREFRESHMANAGER_H diff --git a/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.cpp b/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.cpp index 3b367eda..718e25f3 100644 --- a/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.cpp @@ -35,8 +35,8 @@ */ #include "ScheduledCommand.h" -#include "../TimingCalculation.h" -#include "../../../common/Utils.h" +#include "../timingCalculations.h" +#include "../../../common/rename_utils.h" #include "../configuration/Configuration.h" bool ScheduledCommand::isNoCommand() const diff --git a/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.h b/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.h index c2a5a2fc..aa2f1121 100644 --- a/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.h +++ b/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.h @@ -34,14 +34,14 @@ * Matthias Jung */ -#ifndef SCHEDULEDCOMMAND_H_ -#define SCHEDULEDCOMMAND_H_ +#ifndef SCHEDULEDCOMMAND_H +#define SCHEDULEDCOMMAND_H #include #include #include "../../Command.h" -#include "../../../common/dramExtension.h" -#include "../../../common/Utils.h" +#include "../../../common/dramExtensions.h" +#include "../../../common/rename_utils.h" class ScheduledCommand { @@ -98,5 +98,5 @@ private: DramExtension extension; }; -#endif /* SCHEDULEDCOMMAND_H_ */ +#endif // SCHEDULEDCOMMAND_H diff --git a/DRAMSys/library/src/controller/core/scheduling/Trigger.h b/DRAMSys/library/src/controller/core/scheduling/Trigger.h index b0026be8..3900bdbe 100644 --- a/DRAMSys/library/src/controller/core/scheduling/Trigger.h +++ b/DRAMSys/library/src/controller/core/scheduling/Trigger.h @@ -34,11 +34,11 @@ * Matthias Jung */ -#ifndef TRIGGER_H_ -#define TRIGGER_H_ +#ifndef TRIGGER_H +#define TRIGGER_H enum Trigger {REFTrigger, PDNTrigger}; -#endif /* TRIGGER_H_ */ +#endif // TRIGGER_H diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/ActBChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/ActBChecker.cpp index fff23cde..2313d6cb 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/ActBChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/ActBChecker.cpp @@ -36,10 +36,10 @@ #include #include #include "ActBChecker.h" -#include "../../TimingCalculation.h" +#include "../../timingCalculations.h" #include "../../../../common/DebugManager.h" #include "../../../Command.h" -#include "../../../../common/Utils.h" +#include "../../../../common/rename_utils.h" using namespace std; diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/ActBChecker.h b/DRAMSys/library/src/controller/core/scheduling/checker/ActBChecker.h index 0c83d71d..f1a04859 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/ActBChecker.h +++ b/DRAMSys/library/src/controller/core/scheduling/checker/ActBChecker.h @@ -31,8 +31,9 @@ * * Author: Éder F. Zulian */ -#ifndef ACTB_CHECKER_H_ -#define ACTB_CHECKER_H_ + +#ifndef ACTBCHECKER_H +#define ACTBCHECKER_H #include #include "ICommandChecker.h" @@ -56,4 +57,4 @@ private: bool satisfies_nActivateWindow(ScheduledCommand &command) const; }; -#endif /* ACTB_CHECKER_H_ */ +#endif // ACTBCHECKER_H diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/ActivateChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/ActivateChecker.cpp index 2e29c114..51a10ea7 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/ActivateChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/ActivateChecker.cpp @@ -38,10 +38,10 @@ #include #include #include "ActivateChecker.h" -#include "../../TimingCalculation.h" +#include "../../timingCalculations.h" #include "../../../../common/DebugManager.h" #include "../../../Command.h" -#include "../../../../common/Utils.h" +#include "../../../../common/rename_utils.h" using namespace std; diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/ActivateChecker.h b/DRAMSys/library/src/controller/core/scheduling/checker/ActivateChecker.h index ed62f98d..1312505d 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/ActivateChecker.h +++ b/DRAMSys/library/src/controller/core/scheduling/checker/ActivateChecker.h @@ -34,8 +34,8 @@ * Matthias Jung */ -#ifndef ACTIVATESCHEDULER_H_ -#define ACTIVATESCHEDULER_H_ +#ifndef ACTIVATECHECKER_H +#define ACTIVATECHECKER_H #include #include "ICommandChecker.h" @@ -61,4 +61,4 @@ private: bool satisfies_nActivateWindow(ScheduledCommand &command) const; }; -#endif /* ACTIVATESCHEDULER_H_ */ +#endif // ACTIVATECHECKER_H diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/ICommandChecker.h b/DRAMSys/library/src/controller/core/scheduling/checker/ICommandChecker.h index 833077cb..3f38f93b 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/ICommandChecker.h +++ b/DRAMSys/library/src/controller/core/scheduling/checker/ICommandChecker.h @@ -34,8 +34,8 @@ * Matthias Jung */ -#ifndef ICOMMANDSCHEDULER_H_ -#define ICOMMANDSCHEDULER_H_ +#ifndef ICOMMANDCHECKER_H +#define ICOMMANDCHECKER_H #include #include "../ScheduledCommand.h" @@ -50,4 +50,4 @@ public: -#endif /* ICOMMANDSCHEDULER_H_ */ +#endif // ICOMMANDCHECKER_H diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/PowerDownChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/PowerDownChecker.cpp index 6b92cd96..7a430ac6 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/PowerDownChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/PowerDownChecker.cpp @@ -36,7 +36,7 @@ */ #include "PowerDownChecker.h" -#include "../../TimingCalculation.h" +#include "../../timingCalculations.h" sc_time PowerDownChecker::getTimeConstraintToEnterPowerDown(Command lastCmd, Command pdnCmd) const diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/PowerDownChecker.h b/DRAMSys/library/src/controller/core/scheduling/checker/PowerDownChecker.h index df7a2a9a..a1b5f53d 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/PowerDownChecker.h +++ b/DRAMSys/library/src/controller/core/scheduling/checker/PowerDownChecker.h @@ -34,8 +34,8 @@ * Matthias Jung */ -#ifndef POWERDOWNCHECKER_H_ -#define POWERDOWNCHECKER_H_ +#ifndef POWERDOWNCHECKER_H +#define POWERDOWNCHECKER_H #include @@ -60,5 +60,5 @@ private: Command pdnCmd) const; }; -#endif /* POWERDOWNCHECKER_H_ */ +#endif // POWERDOWNCHECKER_H diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/PreBChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/PreBChecker.cpp index 97c8a103..f559bf38 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/PreBChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/PreBChecker.cpp @@ -33,7 +33,7 @@ */ #include "PreBChecker.h" -#include "../../TimingCalculation.h" +#include "../../timingCalculations.h" void PreBChecker::delayToSatisfyConstraints(ScheduledCommand &cmd) const { sc_assert(cmd.getCommand() == Command::PreB); diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/PreBChecker.h b/DRAMSys/library/src/controller/core/scheduling/checker/PreBChecker.h index f37241d9..980901a3 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/PreBChecker.h +++ b/DRAMSys/library/src/controller/core/scheduling/checker/PreBChecker.h @@ -31,11 +31,14 @@ * * Author: Éder F. Zulian */ -#ifndef PREB_CHECKER_H_ -#define PREB_CHECKER_H_ + +#ifndef PREBCHECKER_H +#define PREBCHECKER_H + #include "ICommandChecker.h" #include "../../configuration/Configuration.h" #include "../../../ControllerState.h" + class PreBChecker: public ICommandChecker { public: @@ -48,4 +51,5 @@ private: const Configuration &config; ControllerState &state; }; -#endif /* PREB_CHECKER_H_ */ + +#endif // PREBCHECKER_H diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/PrechargeAllChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/PrechargeAllChecker.cpp index 31b5732e..f666408d 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/PrechargeAllChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/PrechargeAllChecker.cpp @@ -36,7 +36,7 @@ */ #include "PrechargeAllChecker.h" -#include "../../TimingCalculation.h" +#include "../../timingCalculations.h" void PrechargeAllChecker::delayToSatisfyConstraints(ScheduledCommand &command) diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/PrechargeAllChecker.h b/DRAMSys/library/src/controller/core/scheduling/checker/PrechargeAllChecker.h index 62e8a0f2..41133b4b 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/PrechargeAllChecker.h +++ b/DRAMSys/library/src/controller/core/scheduling/checker/PrechargeAllChecker.h @@ -34,14 +34,13 @@ * Matthias Jung */ -#ifndef PRECHARGEALLCHECKER_H_ -#define PRECHARGEALLCHECKER_H_ +#ifndef PRECHARGEALLCHECKER_H +#define PRECHARGEALLCHECKER_H #include "ICommandChecker.h" #include "../../configuration/Configuration.h" #include "../../../ControllerState.h" - class PrechargeAllChecker: public ICommandChecker { public: @@ -62,4 +61,4 @@ private: }; -#endif /* PRECHARGEALLCHECKER_H_ */ +#endif // PRECHARGEALLCHECKER_H diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/PrechargeChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/PrechargeChecker.cpp index c51fb2b1..6767be1f 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/PrechargeChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/PrechargeChecker.cpp @@ -35,7 +35,7 @@ */ #include "PrechargeChecker.h" -#include "../../TimingCalculation.h" +#include "../../timingCalculations.h" void PrechargeChecker::delayToSatisfyConstraints(ScheduledCommand &command) diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/PrechargeChecker.h b/DRAMSys/library/src/controller/core/scheduling/checker/PrechargeChecker.h index 4977dd55..05b94dc1 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/PrechargeChecker.h +++ b/DRAMSys/library/src/controller/core/scheduling/checker/PrechargeChecker.h @@ -34,14 +34,13 @@ * Matthias Jung */ -#ifndef PRECHARGECHECKER_H_ -#define PRECHARGECHECKER_H_ +#ifndef PRECHARGECHECKER_H +#define PRECHARGECHECKER_H #include "ICommandChecker.h" #include "../../configuration/Configuration.h" #include "../../../ControllerState.h" - class PrechargeChecker: public ICommandChecker { public: @@ -57,4 +56,4 @@ private: }; -#endif /* PRECHARGECHECKER_H_ */ +#endif // PRECHARGECHECKER_ diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/ReadChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/ReadChecker.cpp index b5917e42..f8ea3319 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/ReadChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/ReadChecker.cpp @@ -35,8 +35,8 @@ */ #include "ReadChecker.h" -#include "../../TimingCalculation.h" -#include "../../../../common/Utils.h" +#include "../../timingCalculations.h" +#include "../../../../common/rename_utils.h" #include "WriteChecker.h" using namespace std; diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/ReadChecker.h b/DRAMSys/library/src/controller/core/scheduling/checker/ReadChecker.h index 1fd31f2b..d9c9cce8 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/ReadChecker.h +++ b/DRAMSys/library/src/controller/core/scheduling/checker/ReadChecker.h @@ -34,8 +34,8 @@ * Matthias Jung */ -#ifndef READCHECKER_H_ -#define READCHECKER_H_ +#ifndef READCHECKER_H +#define READCHECKER_H #include "ICommandChecker.h" #include "../../configuration/Configuration.h" @@ -65,5 +65,5 @@ private: ScheduledCommand &strobeCommand) const; }; -#endif /* READCHECKER_H_ */ +#endif // READCHECKER_H diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/RefreshChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/RefreshChecker.cpp index f7d110f0..aad23f4a 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/RefreshChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/RefreshChecker.cpp @@ -36,7 +36,7 @@ */ #include "RefreshChecker.h" -#include "../../TimingCalculation.h" +#include "../../timingCalculations.h" void RefreshChecker::delayToSatisfyConstraints(ScheduledCommand &command) const { diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/RefreshChecker.h b/DRAMSys/library/src/controller/core/scheduling/checker/RefreshChecker.h index 1dd8655d..919531da 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/RefreshChecker.h +++ b/DRAMSys/library/src/controller/core/scheduling/checker/RefreshChecker.h @@ -34,15 +34,14 @@ * Matthias Jung */ -#ifndef REFRESHCHECKER_H_ -#define REFRESHCHECKER_H_ +#ifndef REFRESHCHECKER_H +#define REFRESHCHECKER_H #include "ICommandChecker.h" #include "../../../ControllerState.h" #include "../../configuration/Configuration.h" #include - class RefreshChecker: public ICommandChecker { public: @@ -64,4 +63,4 @@ private: }; -#endif /* REFRESHCHECKER_H_ */ +#endif // REFRESHCHECKER_H diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/WriteChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/WriteChecker.cpp index 226d24aa..d793041b 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/WriteChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/WriteChecker.cpp @@ -35,8 +35,8 @@ */ #include "WriteChecker.h" -#include "../../TimingCalculation.h" -#include "../../../../common/Utils.h" +#include "../../timingCalculations.h" +#include "../../../../common/rename_utils.h" #include "ReadChecker.h" using namespace std; diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/WriteChecker.h b/DRAMSys/library/src/controller/core/scheduling/checker/WriteChecker.h index 5b8c46f8..fa7eafba 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/WriteChecker.h +++ b/DRAMSys/library/src/controller/core/scheduling/checker/WriteChecker.h @@ -34,14 +34,13 @@ * Matthias Jung */ -#ifndef WRITECHECKER_H_ -#define WRITECHECKER_H_ +#ifndef WRITECHECKER_H +#define WRITECHECKER_H #include "ICommandChecker.h" #include "../../configuration/Configuration.h" #include "../../../ControllerState.h" - class WriteChecker: public ICommandChecker { public: @@ -64,4 +63,4 @@ private: }; -#endif /* WRITECHECKER_H_ */ +#endif // WRITECHECKER_H diff --git a/DRAMSys/library/src/controller/core/TimingCalculation.cpp b/DRAMSys/library/src/controller/core/timingCalculations.cpp similarity index 98% rename from DRAMSys/library/src/controller/core/TimingCalculation.cpp rename to DRAMSys/library/src/controller/core/timingCalculations.cpp index 224fd7b1..6a94cbc0 100644 --- a/DRAMSys/library/src/controller/core/TimingCalculation.cpp +++ b/DRAMSys/library/src/controller/core/timingCalculations.cpp @@ -34,12 +34,12 @@ * Matthias Jung */ -#include "TimingCalculation.h" +#include "timingCalculations.h" #include "configuration/MemSpec.h" #include "ControllerCore.h" #include "../../common/DebugManager.h" #include "configuration/Configuration.h" -#include "../../common/Utils.h" +#include "../../common/rename_utils.h" diff --git a/DRAMSys/library/src/controller/core/TimingCalculation.h b/DRAMSys/library/src/controller/core/timingCalculations.h similarity index 94% rename from DRAMSys/library/src/controller/core/TimingCalculation.h rename to DRAMSys/library/src/controller/core/timingCalculations.h index 03fa1918..7a938f8b 100644 --- a/DRAMSys/library/src/controller/core/TimingCalculation.h +++ b/DRAMSys/library/src/controller/core/timingCalculations.h @@ -34,12 +34,12 @@ * Matthias Jung */ -#ifndef UTILS_H_ -#define UTILS_H_ +#ifndef TIMINGCALCULATIONS_H +#define TIMINGCALCULATIONS_H #include #include -#include "../../common/dramExtension.h" +#include "../../common/dramExtensions.h" #include "../Command.h" @@ -56,4 +56,4 @@ const sc_time clkAlign(sc_time time, Alignment alignment = UP); bool isClkAligned(sc_time time, sc_time clk); const sc_time FrequencyToClk(double frequencyMhz); -#endif /* UTILS_H_ */ +#endif // TIMINGCALCULATIONS_H diff --git a/DRAMSys/library/src/controller/scheduler/Fifo.h b/DRAMSys/library/src/controller/scheduler/Fifo.h index 14a9f34c..83f14124 100644 --- a/DRAMSys/library/src/controller/scheduler/Fifo.h +++ b/DRAMSys/library/src/controller/scheduler/Fifo.h @@ -34,8 +34,8 @@ * Matthias Jung */ -#ifndef FIFO_H_ -#define FIFO_H_ +#ifndef FIFO_H +#define FIFO_H #include #include @@ -60,4 +60,4 @@ private: std::map> buffer; }; -#endif /* FIFO_H_ */ +#endif // FIFO_H diff --git a/DRAMSys/library/src/controller/scheduler/FifoStrict.h b/DRAMSys/library/src/controller/scheduler/FifoStrict.h index 4adf3990..2cf8c3dd 100644 --- a/DRAMSys/library/src/controller/scheduler/FifoStrict.h +++ b/DRAMSys/library/src/controller/scheduler/FifoStrict.h @@ -65,5 +65,5 @@ private: std::deque> buffer; }; -#endif /* FIFOSTRICT_H */ +#endif // FIFOSTRICT_H diff --git a/DRAMSys/library/src/controller/scheduler/FrFcfs.cpp b/DRAMSys/library/src/controller/scheduler/FrFcfs.cpp index c51b9192..6aefbe29 100644 --- a/DRAMSys/library/src/controller/scheduler/FrFcfs.cpp +++ b/DRAMSys/library/src/controller/scheduler/FrFcfs.cpp @@ -36,7 +36,7 @@ */ #include "FrFcfs.h" -#include "../../common/dramExtension.h" +#include "../../common/dramExtensions.h" #include "../core/configuration/Configuration.h" #include diff --git a/DRAMSys/library/src/controller/scheduler/FrFcfs.h b/DRAMSys/library/src/controller/scheduler/FrFcfs.h index ea8d250e..92fd34f3 100644 --- a/DRAMSys/library/src/controller/scheduler/FrFcfs.h +++ b/DRAMSys/library/src/controller/scheduler/FrFcfs.h @@ -35,8 +35,8 @@ * Matthias Jung */ -#ifndef FRFCFS_H_ -#define FRFCFS_H_ +#ifndef FRFCFS_H +#define FRFCFS_H #include "IScheduler.h" #include "../core/ControllerCore.h" @@ -63,4 +63,4 @@ private: }; -#endif // FRFCFS_H_ +#endif // FRFCFS_H diff --git a/DRAMSys/library/src/controller/scheduler/IScheduler.h b/DRAMSys/library/src/controller/scheduler/IScheduler.h index 0b0cf0f5..80b6debd 100644 --- a/DRAMSys/library/src/controller/scheduler/IScheduler.h +++ b/DRAMSys/library/src/controller/scheduler/IScheduler.h @@ -40,7 +40,7 @@ #include -#include "../../common/dramExtension.h" +#include "../../common/dramExtensions.h" #include "../Command.h" #include "../core/ControllerCore.h" diff --git a/DRAMSys/library/src/controller/scheduler/SMS.h b/DRAMSys/library/src/controller/scheduler/SMS.h index d60c033a..4019836b 100644 --- a/DRAMSys/library/src/controller/scheduler/SMS.h +++ b/DRAMSys/library/src/controller/scheduler/SMS.h @@ -7,7 +7,7 @@ #include "IScheduler.h" #include "../core/ControllerCore.h" #include "../core/configuration/Configuration.h" -#include "../../common/dramExtension.h" +#include "../../common/dramExtensions.h" #include "../../common/DebugManager.h" #define LOW_SYSTEM_LOAD 16 diff --git a/DRAMSys/library/src/simulation/Arbiter.h b/DRAMSys/library/src/simulation/Arbiter.h index 86d1d1c9..672862c8 100644 --- a/DRAMSys/library/src/simulation/Arbiter.h +++ b/DRAMSys/library/src/simulation/Arbiter.h @@ -35,8 +35,8 @@ * Eder F. Zulian */ -#ifndef ARBITER_H_ -#define ARBITER_H_ +#ifndef ARBITER_H +#define ARBITER_H #include #include @@ -47,8 +47,8 @@ #include #include #include "../common/XmlAddressDecoder.h" -#include "../common/dramExtension.h" -#include "../controller/core/TimingCalculation.h" +#include "../common/dramExtensions.h" +#include "../controller/core/timingCalculations.h" #include "../controller/core/configuration/ConfigurationLoader.h" using namespace std; @@ -102,4 +102,4 @@ private: void printDebugMessage(std::string message); }; -#endif /* ARBITER_H_ */ +#endif // ARBITER_H diff --git a/DRAMSys/library/src/simulation/DRAMSys.cpp b/DRAMSys/library/src/simulation/DRAMSys.cpp index 1e3e5d1b..a01a1cc8 100644 --- a/DRAMSys/library/src/simulation/DRAMSys.cpp +++ b/DRAMSys/library/src/simulation/DRAMSys.cpp @@ -50,7 +50,7 @@ #include "../common/CongenAddressDecoder.h" #include "../controller/core/ControllerCore.h" #include "../controller/core/configuration/ConfigurationLoader.h" -#include "../common/Utils.h" +#include "../common/rename_utils.h" #include "../simulation/TemperatureController.h" #include "../controller/Controller.h" #include "../error/ecchamming.h" diff --git a/DRAMSys/library/src/simulation/DRAMSys.h b/DRAMSys/library/src/simulation/DRAMSys.h index 774e60d3..a2fead62 100644 --- a/DRAMSys/library/src/simulation/DRAMSys.h +++ b/DRAMSys/library/src/simulation/DRAMSys.h @@ -36,8 +36,8 @@ * Felipe S. Prado */ -#ifndef DRAMSYS_H_ -#define DRAMSYS_H_ +#ifndef DRAMSYS_H +#define DRAMSYS_H #include #include @@ -108,4 +108,4 @@ private: void setupDebugManager(const string &traceName); }; -#endif /* SIMULATIONMANAGER_H_ */ +#endif // DRAMSYS_H diff --git a/DRAMSys/library/src/simulation/Dram.cpp b/DRAMSys/library/src/simulation/Dram.cpp index 68b3acb0..0c7388d1 100644 --- a/DRAMSys/library/src/simulation/Dram.cpp +++ b/DRAMSys/library/src/simulation/Dram.cpp @@ -49,12 +49,12 @@ #include #include #include "../common/DebugManager.h" -#include "../common/dramExtension.h" +#include "../common/dramExtensions.h" #include "../controller/Controller.h" -#include "../controller/core/TimingCalculation.h" +#include "../controller/core/timingCalculations.h" #include "../controller/core/configuration/Configuration.h" #include "../common/protocol.h" -#include "../common/Utils.h" +#include "../common/rename_utils.h" #include "../common/third_party/DRAMPower/src/libdrampower/LibDRAMPower.h" #include "../error/errormodel.h" diff --git a/DRAMSys/library/src/simulation/Dram.h b/DRAMSys/library/src/simulation/Dram.h index 20817be9..6712070d 100644 --- a/DRAMSys/library/src/simulation/Dram.h +++ b/DRAMSys/library/src/simulation/Dram.h @@ -37,8 +37,8 @@ * Felipe S. Prado */ -#ifndef DRAM_H_ -#define DRAM_H_ +#ifndef DRAM_H +#define DRAM_H #include #include @@ -97,5 +97,5 @@ public: void setDramController(Controller *contr); }; -#endif /* DRAM_H_ */ +#endif // DRAM_H diff --git a/DRAMSys/library/src/simulation/ExampleInitiator.h b/DRAMSys/library/src/simulation/ExampleInitiator.h index f8b60b9e..6440d5a7 100644 --- a/DRAMSys/library/src/simulation/ExampleInitiator.h +++ b/DRAMSys/library/src/simulation/ExampleInitiator.h @@ -1,11 +1,11 @@ -#ifndef EXAMPLEINITIATOR -#define EXAMPLEINITIATOR +#ifndef EXAMPLEINITIATOR_H +#define EXAMPLEINITIATOR_H #include #include #include "MemoryManager.h" -#include "../common/dramExtension.h" +#include "../common/dramExtensions.h" #include "TracePlayer.h" using namespace std; @@ -202,4 +202,4 @@ struct ExampleInitiator: sc_module { tlm_utils::peq_with_cb_and_phase m_peq; }; -#endif // EXAMPLEINITIATOR +#endif // EXAMPLEINITIATOR_H diff --git a/DRAMSys/library/src/simulation/IArbiter.h b/DRAMSys/library/src/simulation/IArbiter.h index 88c1231b..5dc93a6a 100644 --- a/DRAMSys/library/src/simulation/IArbiter.h +++ b/DRAMSys/library/src/simulation/IArbiter.h @@ -34,8 +34,8 @@ * Matthias Jung */ -#ifndef IARBITER_H_ -#define IARBITER_H_ +#ifndef IARBITER_H +#define IARBITER_H #include #include @@ -139,4 +139,4 @@ protected: } }; -#endif /* IARBITER_H_ */ +#endif // IARBITER_H diff --git a/DRAMSys/library/src/simulation/MemoryManager.h b/DRAMSys/library/src/simulation/MemoryManager.h index 8b431ca5..83baa275 100644 --- a/DRAMSys/library/src/simulation/MemoryManager.h +++ b/DRAMSys/library/src/simulation/MemoryManager.h @@ -34,8 +34,8 @@ * Matthias Jung */ -#ifndef MEMORYMANAGER_H_ -#define MEMORYMANAGER_H_ +#ifndef MEMORYMANAGER_H +#define MEMORYMANAGER_H #include #include @@ -55,4 +55,4 @@ private: std::vector freePayloads; }; -#endif /* MEMORYMANAGER_H_ */ +#endif // MEMORYMANAGER_H diff --git a/DRAMSys/library/src/simulation/RecordableDram.h b/DRAMSys/library/src/simulation/RecordableDram.h index 669eb3cc..191fc868 100644 --- a/DRAMSys/library/src/simulation/RecordableDram.h +++ b/DRAMSys/library/src/simulation/RecordableDram.h @@ -34,8 +34,8 @@ * Matthias Jung */ -#ifndef RECORDABLEDRAM_H_ -#define RECORDABLEDRAM_H_ +#ifndef RECORDABLEDRAM_H +#define RECORDABLEDRAM_H #include "Dram.h" #include "../common/TlmRecorder.h" @@ -74,5 +74,5 @@ private: void recordPower(); }; -#endif /* RECORDABLEDRAM_H_ */ +#endif // RECORDABLEDRAM_H diff --git a/DRAMSys/library/src/simulation/Setup.h b/DRAMSys/library/src/simulation/Setup.h index a8398686..8b8542ce 100644 --- a/DRAMSys/library/src/simulation/Setup.h +++ b/DRAMSys/library/src/simulation/Setup.h @@ -39,7 +39,7 @@ #include #include -#include "../common/Utils.h" +#include "../common/rename_utils.h" #include "TracePlayer.h" #include "StlPlayer.h" diff --git a/DRAMSys/library/src/simulation/SimpleArbiter.h b/DRAMSys/library/src/simulation/SimpleArbiter.h index bc2f7b9e..5434576b 100644 --- a/DRAMSys/library/src/simulation/SimpleArbiter.h +++ b/DRAMSys/library/src/simulation/SimpleArbiter.h @@ -39,8 +39,8 @@ #include "IArbiter.h" #include "../common/XmlAddressDecoder.h" -#include "../common/dramExtension.h" -#include "../controller/core/TimingCalculation.h" +#include "../common/dramExtensions.h" +#include "../controller/core/timingCalculations.h" using namespace std; using namespace tlm; diff --git a/DRAMSys/library/src/simulation/TemperatureController.h b/DRAMSys/library/src/simulation/TemperatureController.h index d26dc2d7..3f510d97 100644 --- a/DRAMSys/library/src/simulation/TemperatureController.h +++ b/DRAMSys/library/src/simulation/TemperatureController.h @@ -34,8 +34,8 @@ * Matthias Jung */ -#ifndef TEMPERATURE_CONTROLLER_H_ -#define TEMPERATURE_CONTROLLER_H_ +#ifndef TEMPERATURECONTROLLER_H +#define TEMPERATURECONTROLLER_H #include #include @@ -43,7 +43,7 @@ #include #include "../common/DebugManager.h" -#include "../common/Utils.h" +#include "../common/rename_utils.h" #include "../controller/core/configuration/Configuration.h" #ifdef THERMALSIM @@ -152,5 +152,5 @@ private: void printDebugMessage(std::string message); }; -#endif /* TEMPERATURE_CONTROLLER_H_ */ +#endif // TEMPERATURECONTROLLER_H diff --git a/DRAMSys/library/src/simulation/TraceGenerator.h b/DRAMSys/library/src/simulation/TraceGenerator.h index 04d9cc49..3019b6f5 100644 --- a/DRAMSys/library/src/simulation/TraceGenerator.h +++ b/DRAMSys/library/src/simulation/TraceGenerator.h @@ -86,5 +86,5 @@ private: unsigned int transCounter; }; -#endif +#endif // TRACEGENERATOR_H diff --git a/DRAMSys/library/src/simulation/TracePlayer.h b/DRAMSys/library/src/simulation/TracePlayer.h index 5adbd09e..5a34df28 100644 --- a/DRAMSys/library/src/simulation/TracePlayer.h +++ b/DRAMSys/library/src/simulation/TracePlayer.h @@ -36,8 +36,8 @@ * Felipe S. Prado */ -#ifndef TRACEPLAYER_H_ -#define TRACEPLAYER_H_ +#ifndef TRACEPLAYER_H +#define TRACEPLAYER_H #include #include @@ -50,7 +50,7 @@ #include "../controller/core/configuration/Configuration.h" #include "../common/DebugManager.h" #include "../common/XmlAddressDecoder.h" -#include "../controller/core/TimingCalculation.h" +#include "../controller/core/timingCalculations.h" #include "TracePlayerListener.h" using namespace std; @@ -85,4 +85,4 @@ private: bool finished; }; -#endif /* TRACEPLAYER_H_ */ +#endif // TRACEPLAYER_H diff --git a/DRAMSys/library/src/simulation/TraceSetup.h b/DRAMSys/library/src/simulation/TraceSetup.h index 901b6756..c4c39279 100644 --- a/DRAMSys/library/src/simulation/TraceSetup.h +++ b/DRAMSys/library/src/simulation/TraceSetup.h @@ -39,7 +39,7 @@ #include #include -#include "../common/Utils.h" +#include "../common/rename_utils.h" #include "TracePlayer.h" #include "StlPlayer.h" From abcd2a910bfc520450e5363b37d1b02654944ac5 Mon Sep 17 00:00:00 2001 From: Lukas Steiner Date: Wed, 12 Jun 2019 20:25:38 +0200 Subject: [PATCH 80/97] Renaming files (Commit 2 of 2) --- DRAMSys/library/library.pro | 11 +++-- .../src/common/CongenAddressDecoder.cpp | 2 +- .../library/src/common/CongenAddressDecoder.h | 3 +- DRAMSys/library/src/common/DebugManager.h | 2 +- DRAMSys/library/src/common/TlmRecorder.h | 2 +- .../library/src/common/XmlAddressDecoder.cpp | 2 +- .../library/src/common/XmlAddressDecoder.h | 5 +-- DRAMSys/library/src/common/dramExtensions.cpp | 2 +- DRAMSys/library/src/common/dramExtensions.h | 1 - .../common/{rename_utils.cpp => utils.cpp} | 2 +- .../src/common/{rename_utils.h => utils.h} | 0 DRAMSys/library/src/controller/Command.h | 1 - DRAMSys/library/src/controller/Controller.h | 3 +- DRAMSys/library/src/controller/IController.h | 2 +- .../src/controller/RowBufferStates.cpp | 2 +- .../src/controller/core/ControllerCore.cpp | 2 +- .../core/configuration/Configuration.h | 4 +- .../core/configuration/ConfigurationLoader.h | 2 +- .../controller/core/configuration/MemSpec.h | 7 ++- ...rmalSimConfig.h => TemperatureSimConfig.h} | 12 ++--- .../controller/core/powerdown/NoPowerDown.h | 2 +- .../core/powerdown/PowerDownManager.cpp | 2 +- .../powerdown/PowerDownManagerBankwise.cpp | 2 +- .../powerdown/PowerDownManagerTimeout.cpp | 2 +- .../PowerDownManagerTimeoutBankwise.cpp | 2 +- .../src/controller/core/refresh/RGR.cpp | 2 +- .../core/refresh/RefreshManager.cpp | 2 +- .../core/refresh/RefreshManagerBankwise.cpp | 2 +- .../core/refresh/RefreshManagerBankwise.h | 6 +-- .../core/scheduling/ScheduledCommand.cpp | 2 +- .../core/scheduling/ScheduledCommand.h | 2 +- .../src/controller/core/scheduling/Trigger.h | 44 ------------------- .../core/scheduling/checker/ActBChecker.cpp | 2 +- .../scheduling/checker/ActivateChecker.cpp | 2 +- .../core/scheduling/checker/ReadChecker.cpp | 2 +- .../core/scheduling/checker/RefreshChecker.h | 2 +- .../core/scheduling/checker/WriteChecker.cpp | 2 +- .../core/scheduling/checker/WriteChecker.h | 2 +- .../controller/core/timingCalculations.cpp | 2 +- .../src/controller/core/timingCalculations.h | 1 - .../src/controller/scheduler/IScheduler.h | 1 - DRAMSys/library/src/simulation/DRAMSys.cpp | 2 +- DRAMSys/library/src/simulation/DRAMSys.h | 2 +- DRAMSys/library/src/simulation/Dram.cpp | 2 +- .../library/src/simulation/ExampleInitiator.h | 3 +- DRAMSys/library/src/simulation/IArbiter.h | 3 +- DRAMSys/library/src/simulation/Setup.h | 2 +- DRAMSys/library/src/simulation/StlPlayer.h | 3 +- .../src/simulation/TemperatureController.h | 2 +- .../library/src/simulation/TraceGenerator.h | 4 +- DRAMSys/library/src/simulation/TracePlayer.h | 3 +- DRAMSys/library/src/simulation/TraceSetup.h | 2 +- 52 files changed, 66 insertions(+), 115 deletions(-) rename DRAMSys/library/src/common/{rename_utils.cpp => utils.cpp} (99%) rename DRAMSys/library/src/common/{rename_utils.h => utils.h} (100%) rename DRAMSys/library/src/controller/core/configuration/{thermalSimConfig.h => TemperatureSimConfig.h} (96%) delete mode 100644 DRAMSys/library/src/controller/core/scheduling/Trigger.h diff --git a/DRAMSys/library/library.pro b/DRAMSys/library/library.pro index 2c4050f5..ab7ca602 100644 --- a/DRAMSys/library/library.pro +++ b/DRAMSys/library/library.pro @@ -141,9 +141,9 @@ SOURCES += \ src/simulation/Arbiter.cpp \ src/common/CongenAddressDecoder.cpp \ src/common/XmlAddressDecoder.cpp \ - src/common/rename_utils.cpp \ src/controller/core/timingCalculations.cpp \ - src/common/dramExtensions.cpp + src/common/dramExtensions.cpp \ + src/common/utils.cpp HEADERS += \ src/common/third_party/tinyxml2/tinyxml2.h \ @@ -173,7 +173,6 @@ HEADERS += \ src/controller/core/scheduling/checker/ActivateChecker.h \ src/controller/core/scheduling/checker/PreBChecker.h \ src/controller/core/scheduling/checker/ActBChecker.h \ - src/controller/core/scheduling/Trigger.h \ src/controller/core/scheduling/ScheduledCommand.h \ src/controller/core/Slots.h \ src/controller/core/ControllerCore.h \ @@ -184,7 +183,6 @@ HEADERS += \ src/common/libDRAMPower.h \ src/simulation/ReorderBuffer.h \ src/controller/core/configuration/MemSpec.h \ - src/controller/core/configuration/thermalSimConfig.h \ src/simulation/StlPlayer.h \ src/simulation/TracePlayerListener.h \ src/simulation/TraceGenerator.h \ @@ -219,9 +217,10 @@ HEADERS += \ src/common/AddressDecoder.h \ src/common/CongenAddressDecoder.h \ src/common/XmlAddressDecoder.h \ - src/common/rename_utils.h \ src/controller/core/timingCalculations.h \ - src/common/dramExtensions.h + src/common/dramExtensions.h \ + src/common/utils.h \ + src/controller/core/configuration/TemperatureSimConfig.h #src/common/third_party/json/include/nlohmann/json.hpp \ thermalsim = $$(THERMALSIM) diff --git a/DRAMSys/library/src/common/CongenAddressDecoder.cpp b/DRAMSys/library/src/common/CongenAddressDecoder.cpp index 8ca2ce74..ea11dcbc 100644 --- a/DRAMSys/library/src/common/CongenAddressDecoder.cpp +++ b/DRAMSys/library/src/common/CongenAddressDecoder.cpp @@ -34,7 +34,7 @@ */ #include "CongenAddressDecoder.h" -#include "rename_utils.h" +#include "utils.h" #include diff --git a/DRAMSys/library/src/common/CongenAddressDecoder.h b/DRAMSys/library/src/common/CongenAddressDecoder.h index e2d210a5..51778ecf 100644 --- a/DRAMSys/library/src/common/CongenAddressDecoder.h +++ b/DRAMSys/library/src/common/CongenAddressDecoder.h @@ -47,8 +47,7 @@ using std::vector; using std::pair; using std::map; -class CongenAddressDecoder - : private AddressDecoder +class CongenAddressDecoder : private AddressDecoder { // Friendship needed so that the AddressDecoder can access the // constructor of this class to create the object in CreateInstance. diff --git a/DRAMSys/library/src/common/DebugManager.h b/DRAMSys/library/src/common/DebugManager.h index f3810dee..dd35b796 100644 --- a/DRAMSys/library/src/common/DebugManager.h +++ b/DRAMSys/library/src/common/DebugManager.h @@ -40,7 +40,7 @@ #include #include #include -#include "rename_utils.h" +#include "utils.h" class DebugManager { diff --git a/DRAMSys/library/src/common/TlmRecorder.h b/DRAMSys/library/src/common/TlmRecorder.h index 8b8ef016..c69ad4f6 100644 --- a/DRAMSys/library/src/common/TlmRecorder.h +++ b/DRAMSys/library/src/common/TlmRecorder.h @@ -51,7 +51,7 @@ #include #include "XmlAddressDecoder.h" #include "DebugManager.h" -#include "rename_utils.h" +#include "utils.h" using namespace std; diff --git a/DRAMSys/library/src/common/XmlAddressDecoder.cpp b/DRAMSys/library/src/common/XmlAddressDecoder.cpp index caa49062..f94011d2 100644 --- a/DRAMSys/library/src/common/XmlAddressDecoder.cpp +++ b/DRAMSys/library/src/common/XmlAddressDecoder.cpp @@ -37,7 +37,7 @@ #include "XmlAddressDecoder.h" #include -#include "rename_utils.h" +#include "utils.h" #include "bitset" #include "../controller/core/configuration/Configuration.h" diff --git a/DRAMSys/library/src/common/XmlAddressDecoder.h b/DRAMSys/library/src/common/XmlAddressDecoder.h index 488eb4a7..dfd65072 100644 --- a/DRAMSys/library/src/common/XmlAddressDecoder.h +++ b/DRAMSys/library/src/common/XmlAddressDecoder.h @@ -40,12 +40,11 @@ #include -#include "rename_utils.h" +#include "utils.h" #include "third_party/tinyxml2/tinyxml2.h" #include "AddressDecoder.h" -class XmlAddressDecoder - : private AddressDecoder +class XmlAddressDecoder : private AddressDecoder { // Friendship needed so that the AddressDecoder can access the // constructor of this class to create the object in CreateInstance. diff --git a/DRAMSys/library/src/common/dramExtensions.cpp b/DRAMSys/library/src/common/dramExtensions.cpp index 51ee8578..9a2b9da3 100644 --- a/DRAMSys/library/src/common/dramExtensions.cpp +++ b/DRAMSys/library/src/common/dramExtensions.cpp @@ -38,7 +38,7 @@ #include "dramExtensions.h" #include "../controller/core/configuration/Configuration.h" #include "map" -#include "rename_utils.h" +#include "utils.h" using namespace tlm; diff --git a/DRAMSys/library/src/common/dramExtensions.h b/DRAMSys/library/src/common/dramExtensions.h index 2f62ab94..3a4b1a51 100644 --- a/DRAMSys/library/src/common/dramExtensions.h +++ b/DRAMSys/library/src/common/dramExtensions.h @@ -41,7 +41,6 @@ #include #include - class Thread { public: diff --git a/DRAMSys/library/src/common/rename_utils.cpp b/DRAMSys/library/src/common/utils.cpp similarity index 99% rename from DRAMSys/library/src/common/rename_utils.cpp rename to DRAMSys/library/src/common/utils.cpp index 9e0c19a8..69c6f899 100644 --- a/DRAMSys/library/src/common/rename_utils.cpp +++ b/DRAMSys/library/src/common/utils.cpp @@ -35,7 +35,7 @@ * Matthias Jung */ -#include "rename_utils.h" +#include "utils.h" #include #include #include diff --git a/DRAMSys/library/src/common/rename_utils.h b/DRAMSys/library/src/common/utils.h similarity index 100% rename from DRAMSys/library/src/common/rename_utils.h rename to DRAMSys/library/src/common/utils.h diff --git a/DRAMSys/library/src/controller/Command.h b/DRAMSys/library/src/controller/Command.h index c2b87464..e8aa28e7 100644 --- a/DRAMSys/library/src/controller/Command.h +++ b/DRAMSys/library/src/controller/Command.h @@ -39,7 +39,6 @@ #include #include - enum class Command { NOP, PreB, diff --git a/DRAMSys/library/src/controller/Controller.h b/DRAMSys/library/src/controller/Controller.h index 0a743632..133f10f9 100644 --- a/DRAMSys/library/src/controller/Controller.h +++ b/DRAMSys/library/src/controller/Controller.h @@ -53,7 +53,7 @@ #include "../common/DebugManager.h" #include "../common/protocol.h" #include "../common/TlmRecorder.h" -#include "../common/rename_utils.h" +#include "../common/utils.h" #include "core/configuration/Configuration.h" #include "core/configuration/MemSpec.h" #include "Command.h" @@ -62,7 +62,6 @@ #include "IController.h" #include "core/powerdown/IPowerDownManager.h" #include "core/scheduling/ScheduledCommand.h" -#include "core/scheduling/Trigger.h" #include "core/timingCalculations.h" #include "scheduler/Fifo.h" #include "scheduler/Grp.h" diff --git a/DRAMSys/library/src/controller/IController.h b/DRAMSys/library/src/controller/IController.h index 4504c4c3..b61fc0d7 100644 --- a/DRAMSys/library/src/controller/IController.h +++ b/DRAMSys/library/src/controller/IController.h @@ -41,9 +41,9 @@ #include #include #include "core/scheduling/ScheduledCommand.h" -#include "core/scheduling/Trigger.h" #include "../common/dramExtensions.h" +enum Trigger {REFTrigger, PDNTrigger}; // Utiliy class to pass around the Controller class to the controller Core and various schedulers, without having to propagate the template defintions // throughout all classes diff --git a/DRAMSys/library/src/controller/RowBufferStates.cpp b/DRAMSys/library/src/controller/RowBufferStates.cpp index 4c57d257..e47f5298 100644 --- a/DRAMSys/library/src/controller/RowBufferStates.cpp +++ b/DRAMSys/library/src/controller/RowBufferStates.cpp @@ -37,7 +37,7 @@ #include "RowBufferStates.h" #include "core/ControllerCore.h" #include "../common/DebugManager.h" -#include "../common/rename_utils.h" +#include "../common/utils.h" using namespace std; diff --git a/DRAMSys/library/src/controller/core/ControllerCore.cpp b/DRAMSys/library/src/controller/core/ControllerCore.cpp index 92dfe1a1..f966c965 100644 --- a/DRAMSys/library/src/controller/core/ControllerCore.cpp +++ b/DRAMSys/library/src/controller/core/ControllerCore.cpp @@ -50,7 +50,7 @@ #include "refresh/RefreshManager.h" #include "refresh/RGR.h" #include "../../common/dramExtensions.h" -#include "../../common/rename_utils.h" +#include "../../common/utils.h" #include "timingCalculations.h" #include "powerdown/PowerDownManager.h" diff --git a/DRAMSys/library/src/controller/core/configuration/Configuration.h b/DRAMSys/library/src/controller/core/configuration/Configuration.h index 6472a4c5..bd1e4bfe 100644 --- a/DRAMSys/library/src/controller/core/configuration/Configuration.h +++ b/DRAMSys/library/src/controller/core/configuration/Configuration.h @@ -43,8 +43,8 @@ #include #include #include "MemSpec.h" -#include "thermalSimConfig.h" -#include "../../../common/rename_utils.h" +#include "TemperatureSimConfig.h" +#include "../../../common/utils.h" #include "../../../error/eccbaseclass.h" diff --git a/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.h b/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.h index fe701b59..c4b77530 100644 --- a/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.h +++ b/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.h @@ -39,7 +39,7 @@ #include #include "../../../common/third_party/tinyxml2/tinyxml2.h" -#include "../../../common/rename_utils.h" +#include "../../../common/utils.h" #include "Configuration.h" class ConfigurationLoader diff --git a/DRAMSys/library/src/controller/core/configuration/MemSpec.h b/DRAMSys/library/src/controller/core/configuration/MemSpec.h index 79b10329..9a5e06d5 100644 --- a/DRAMSys/library/src/controller/core/configuration/MemSpec.h +++ b/DRAMSys/library/src/controller/core/configuration/MemSpec.h @@ -34,14 +34,13 @@ * Matthias Jung */ -#ifndef MemSpec_H_ -#define MemSpec_H_ +#ifndef MEMSPEC_H +#define MEMSPEC_H #include #include #include "../../../common/dramExtensions.h" - struct RefreshTiming { RefreshTiming() {} RefreshTiming(sc_time tRFC, sc_time tREFI) : tRFC(tRFC), tRFC2(SC_ZERO_TIME), @@ -165,5 +164,5 @@ struct MemSpec { } }; -#endif /* MemSpec_H_ */ +#endif // MEMSPEC_H diff --git a/DRAMSys/library/src/controller/core/configuration/thermalSimConfig.h b/DRAMSys/library/src/controller/core/configuration/TemperatureSimConfig.h similarity index 96% rename from DRAMSys/library/src/controller/core/configuration/thermalSimConfig.h rename to DRAMSys/library/src/controller/core/configuration/TemperatureSimConfig.h index 8d13a77d..b9acd733 100644 --- a/DRAMSys/library/src/controller/core/configuration/thermalSimConfig.h +++ b/DRAMSys/library/src/controller/core/configuration/TemperatureSimConfig.h @@ -34,8 +34,8 @@ * Matthias Jung */ -#ifndef THERMALSIM_CONFIG_H -#define THERMALSIM_CONFIG_H +#ifndef TEMPERATURESIMCONFIG_H +#define TEMPERATURESIMCONFIG_H #include #include @@ -43,10 +43,10 @@ #include "../../../common/DebugManager.h" #include "../../../common/third_party/tinyxml2/tinyxml2.h" -#include "../../../common/rename_utils.h" - -struct TemperatureSimConfig { +#include "../../../common/utils.h" +struct TemperatureSimConfig +{ // Temperature Scale std::string TemperatureScale; std::string pathToResources; @@ -132,5 +132,5 @@ struct TemperatureSimConfig { } }; -#endif /* THERMALSIM_CONFIG_H */ +#endif // TEMPERATURESIMCONFIG_H diff --git a/DRAMSys/library/src/controller/core/powerdown/NoPowerDown.h b/DRAMSys/library/src/controller/core/powerdown/NoPowerDown.h index e68d344a..19a53403 100644 --- a/DRAMSys/library/src/controller/core/powerdown/NoPowerDown.h +++ b/DRAMSys/library/src/controller/core/powerdown/NoPowerDown.h @@ -45,7 +45,7 @@ -class NoPowerDown: public IPowerDownManager +class NoPowerDown : public IPowerDownManager { public: NoPowerDown() {} diff --git a/DRAMSys/library/src/controller/core/powerdown/PowerDownManager.cpp b/DRAMSys/library/src/controller/core/powerdown/PowerDownManager.cpp index 9d3a5258..d5281e05 100644 --- a/DRAMSys/library/src/controller/core/powerdown/PowerDownManager.cpp +++ b/DRAMSys/library/src/controller/core/powerdown/PowerDownManager.cpp @@ -42,7 +42,7 @@ #include "../timingCalculations.h" #include "../../../common/DebugManager.h" #include -#include "../../../common/rename_utils.h" +#include "../../../common/utils.h" using namespace tlm; using namespace std; diff --git a/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerBankwise.cpp b/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerBankwise.cpp index 344b1700..a73d7674 100644 --- a/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerBankwise.cpp +++ b/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerBankwise.cpp @@ -36,7 +36,7 @@ #include "PowerDownManager.h" #include "../ControllerCore.h" -#include "../../../common/rename_utils.h" +#include "../../../common/utils.h" #include "../../../common/DebugManager.h" #include "../timingCalculations.h" diff --git a/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerTimeout.cpp b/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerTimeout.cpp index 88a97766..997e9c37 100644 --- a/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerTimeout.cpp +++ b/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerTimeout.cpp @@ -38,7 +38,7 @@ #include "PowerDownManagerTimeout.h" #include "../ControllerCore.h" -#include "../../../common/rename_utils.h" +#include "../../../common/utils.h" #include "../../../common/DebugManager.h" #include "../timingCalculations.h" diff --git a/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerTimeoutBankwise.cpp b/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerTimeoutBankwise.cpp index 2e4a2a1a..cd743e02 100644 --- a/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerTimeoutBankwise.cpp +++ b/DRAMSys/library/src/controller/core/powerdown/PowerDownManagerTimeoutBankwise.cpp @@ -38,7 +38,7 @@ #include "PowerDownManagerTimeoutBankwise.h" #include "../ControllerCore.h" -#include "../../../common/rename_utils.h" +#include "../../../common/utils.h" #include "../../../common/DebugManager.h" #include "../timingCalculations.h" diff --git a/DRAMSys/library/src/controller/core/refresh/RGR.cpp b/DRAMSys/library/src/controller/core/refresh/RGR.cpp index ff4c72e5..e7f5b652 100644 --- a/DRAMSys/library/src/controller/core/refresh/RGR.cpp +++ b/DRAMSys/library/src/controller/core/refresh/RGR.cpp @@ -37,7 +37,7 @@ #include "RGR.h" #include "../ControllerCore.h" #include "../timingCalculations.h" -#include "../../../common/rename_utils.h" +#include "../../../common/utils.h" #define TRUE 1 #define FALSE !(TRUE) diff --git a/DRAMSys/library/src/controller/core/refresh/RefreshManager.cpp b/DRAMSys/library/src/controller/core/refresh/RefreshManager.cpp index ad1cea5b..8b4981ec 100644 --- a/DRAMSys/library/src/controller/core/refresh/RefreshManager.cpp +++ b/DRAMSys/library/src/controller/core/refresh/RefreshManager.cpp @@ -40,7 +40,7 @@ #include "RefreshManager.h" #include "../ControllerCore.h" #include "../timingCalculations.h" -#include "../../../common/rename_utils.h" +#include "../../../common/utils.h" using namespace tlm; diff --git a/DRAMSys/library/src/controller/core/refresh/RefreshManagerBankwise.cpp b/DRAMSys/library/src/controller/core/refresh/RefreshManagerBankwise.cpp index ab878ff0..a496ab8e 100644 --- a/DRAMSys/library/src/controller/core/refresh/RefreshManagerBankwise.cpp +++ b/DRAMSys/library/src/controller/core/refresh/RefreshManagerBankwise.cpp @@ -38,7 +38,7 @@ #include "RefreshManagerBankwise.h" #include "../ControllerCore.h" #include "../timingCalculations.h" -#include "../../../common/rename_utils.h" +#include "../../../common/utils.h" using namespace std; diff --git a/DRAMSys/library/src/controller/core/refresh/RefreshManagerBankwise.h b/DRAMSys/library/src/controller/core/refresh/RefreshManagerBankwise.h index 1c84d83e..a4728f4e 100644 --- a/DRAMSys/library/src/controller/core/refresh/RefreshManagerBankwise.h +++ b/DRAMSys/library/src/controller/core/refresh/RefreshManagerBankwise.h @@ -35,8 +35,8 @@ * Éder F. Zulian */ -#ifndef BANKWISEREFRESHMANAGER_H -#define BANKWISEREFRESHMANAGER_H +#ifndef REFRESHMANAGERBANKWISE_H +#define REFRESHMANAGERBANKWISE_H //#include "../../../common/dramExtension.h" #include "IRefreshManager.h" @@ -79,5 +79,5 @@ private: void printDebugMessage(std::string message); }; -#endif // BANKWISEREFRESHMANAGER_H +#endif // REFRESHMANAGERBANKWISE_H diff --git a/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.cpp b/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.cpp index 718e25f3..2945cc74 100644 --- a/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.cpp @@ -36,7 +36,7 @@ #include "ScheduledCommand.h" #include "../timingCalculations.h" -#include "../../../common/rename_utils.h" +#include "../../../common/utils.h" #include "../configuration/Configuration.h" bool ScheduledCommand::isNoCommand() const diff --git a/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.h b/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.h index aa2f1121..bc4721b7 100644 --- a/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.h +++ b/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.h @@ -41,7 +41,7 @@ #include #include "../../Command.h" #include "../../../common/dramExtensions.h" -#include "../../../common/rename_utils.h" +#include "../../../common/utils.h" class ScheduledCommand { diff --git a/DRAMSys/library/src/controller/core/scheduling/Trigger.h b/DRAMSys/library/src/controller/core/scheduling/Trigger.h deleted file mode 100644 index 3900bdbe..00000000 --- a/DRAMSys/library/src/controller/core/scheduling/Trigger.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2015, University of Kaiserslautern - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: - * Janik Schlemminger - * Matthias Jung - */ - -#ifndef TRIGGER_H -#define TRIGGER_H - - -enum Trigger {REFTrigger, PDNTrigger}; - - -#endif // TRIGGER_H diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/ActBChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/ActBChecker.cpp index 2313d6cb..55edd9a9 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/ActBChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/ActBChecker.cpp @@ -39,7 +39,7 @@ #include "../../timingCalculations.h" #include "../../../../common/DebugManager.h" #include "../../../Command.h" -#include "../../../../common/rename_utils.h" +#include "../../../../common/utils.h" using namespace std; diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/ActivateChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/ActivateChecker.cpp index 51a10ea7..18236ba3 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/ActivateChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/ActivateChecker.cpp @@ -41,7 +41,7 @@ #include "../../timingCalculations.h" #include "../../../../common/DebugManager.h" #include "../../../Command.h" -#include "../../../../common/rename_utils.h" +#include "../../../../common/utils.h" using namespace std; diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/ReadChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/ReadChecker.cpp index f8ea3319..048f5cd5 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/ReadChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/ReadChecker.cpp @@ -36,7 +36,7 @@ #include "ReadChecker.h" #include "../../timingCalculations.h" -#include "../../../../common/rename_utils.h" +#include "../../../../common/utils.h" #include "WriteChecker.h" using namespace std; diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/RefreshChecker.h b/DRAMSys/library/src/controller/core/scheduling/checker/RefreshChecker.h index 919531da..ae7a4c9e 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/RefreshChecker.h +++ b/DRAMSys/library/src/controller/core/scheduling/checker/RefreshChecker.h @@ -42,7 +42,7 @@ #include "../../configuration/Configuration.h" #include -class RefreshChecker: public ICommandChecker +class RefreshChecker : public ICommandChecker { public: RefreshChecker(const Configuration &config, ControllerState &state) : diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/WriteChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/WriteChecker.cpp index d793041b..b2aed2d2 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/WriteChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/WriteChecker.cpp @@ -36,7 +36,7 @@ #include "WriteChecker.h" #include "../../timingCalculations.h" -#include "../../../../common/rename_utils.h" +#include "../../../../common/utils.h" #include "ReadChecker.h" using namespace std; diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/WriteChecker.h b/DRAMSys/library/src/controller/core/scheduling/checker/WriteChecker.h index fa7eafba..4bddeb69 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/WriteChecker.h +++ b/DRAMSys/library/src/controller/core/scheduling/checker/WriteChecker.h @@ -41,7 +41,7 @@ #include "../../configuration/Configuration.h" #include "../../../ControllerState.h" -class WriteChecker: public ICommandChecker +class WriteChecker : public ICommandChecker { public: WriteChecker(const Configuration &config, diff --git a/DRAMSys/library/src/controller/core/timingCalculations.cpp b/DRAMSys/library/src/controller/core/timingCalculations.cpp index 6a94cbc0..2f4b65cb 100644 --- a/DRAMSys/library/src/controller/core/timingCalculations.cpp +++ b/DRAMSys/library/src/controller/core/timingCalculations.cpp @@ -39,7 +39,7 @@ #include "ControllerCore.h" #include "../../common/DebugManager.h" #include "configuration/Configuration.h" -#include "../../common/rename_utils.h" +#include "../../common/utils.h" diff --git a/DRAMSys/library/src/controller/core/timingCalculations.h b/DRAMSys/library/src/controller/core/timingCalculations.h index 7a938f8b..e9f80d4e 100644 --- a/DRAMSys/library/src/controller/core/timingCalculations.h +++ b/DRAMSys/library/src/controller/core/timingCalculations.h @@ -42,7 +42,6 @@ #include "../../common/dramExtensions.h" #include "../Command.h" - sc_time getMinExecutionTimeForPowerDownCmd(Command command); sc_time getExecutionTime(Command command, tlm::tlm_generic_payload &payload); diff --git a/DRAMSys/library/src/controller/scheduler/IScheduler.h b/DRAMSys/library/src/controller/scheduler/IScheduler.h index 80b6debd..b40f29ec 100644 --- a/DRAMSys/library/src/controller/scheduler/IScheduler.h +++ b/DRAMSys/library/src/controller/scheduler/IScheduler.h @@ -38,7 +38,6 @@ #ifndef ISCHEDULER_H #define ISCHEDULER_H - #include #include "../../common/dramExtensions.h" #include "../Command.h" diff --git a/DRAMSys/library/src/simulation/DRAMSys.cpp b/DRAMSys/library/src/simulation/DRAMSys.cpp index a01a1cc8..46be1af4 100644 --- a/DRAMSys/library/src/simulation/DRAMSys.cpp +++ b/DRAMSys/library/src/simulation/DRAMSys.cpp @@ -50,7 +50,7 @@ #include "../common/CongenAddressDecoder.h" #include "../controller/core/ControllerCore.h" #include "../controller/core/configuration/ConfigurationLoader.h" -#include "../common/rename_utils.h" +#include "../common/utils.h" #include "../simulation/TemperatureController.h" #include "../controller/Controller.h" #include "../error/ecchamming.h" diff --git a/DRAMSys/library/src/simulation/DRAMSys.h b/DRAMSys/library/src/simulation/DRAMSys.h index a2fead62..288820e8 100644 --- a/DRAMSys/library/src/simulation/DRAMSys.h +++ b/DRAMSys/library/src/simulation/DRAMSys.h @@ -53,7 +53,7 @@ #include "../common/tlm2_base_protocol_checker.h" #include "../error/eccbaseclass.h" -class DRAMSys: public sc_module +class DRAMSys : public sc_module { public: tlm_utils::multi_passthrough_target_socket tSocket; diff --git a/DRAMSys/library/src/simulation/Dram.cpp b/DRAMSys/library/src/simulation/Dram.cpp index 0c7388d1..e18f1456 100644 --- a/DRAMSys/library/src/simulation/Dram.cpp +++ b/DRAMSys/library/src/simulation/Dram.cpp @@ -54,7 +54,7 @@ #include "../controller/core/timingCalculations.h" #include "../controller/core/configuration/Configuration.h" #include "../common/protocol.h" -#include "../common/rename_utils.h" +#include "../common/utils.h" #include "../common/third_party/DRAMPower/src/libdrampower/LibDRAMPower.h" #include "../error/errormodel.h" diff --git a/DRAMSys/library/src/simulation/ExampleInitiator.h b/DRAMSys/library/src/simulation/ExampleInitiator.h index 6440d5a7..7b227709 100644 --- a/DRAMSys/library/src/simulation/ExampleInitiator.h +++ b/DRAMSys/library/src/simulation/ExampleInitiator.h @@ -10,7 +10,8 @@ using namespace std; -struct ExampleInitiator: sc_module { +struct ExampleInitiator : sc_module +{ // TLM-2 socket, defaults to 32-bits wide, base protocol tlm_utils::simple_initiator_socket socket; diff --git a/DRAMSys/library/src/simulation/IArbiter.h b/DRAMSys/library/src/simulation/IArbiter.h index 5dc93a6a..872fd929 100644 --- a/DRAMSys/library/src/simulation/IArbiter.h +++ b/DRAMSys/library/src/simulation/IArbiter.h @@ -49,7 +49,8 @@ using namespace std; using namespace tlm; -struct IArbiter: public sc_module { +struct IArbiter : public sc_module +{ public: tlm_utils::multi_passthrough_target_socket tSocket; tlm_utils::multi_passthrough_initiator_socket iSocket; diff --git a/DRAMSys/library/src/simulation/Setup.h b/DRAMSys/library/src/simulation/Setup.h index 8b8542ce..34d064e1 100644 --- a/DRAMSys/library/src/simulation/Setup.h +++ b/DRAMSys/library/src/simulation/Setup.h @@ -39,7 +39,7 @@ #include #include -#include "../common/rename_utils.h" +#include "../common/utils.h" #include "TracePlayer.h" #include "StlPlayer.h" diff --git a/DRAMSys/library/src/simulation/StlPlayer.h b/DRAMSys/library/src/simulation/StlPlayer.h index b8b0e9a8..b8e23bbd 100644 --- a/DRAMSys/library/src/simulation/StlPlayer.h +++ b/DRAMSys/library/src/simulation/StlPlayer.h @@ -46,7 +46,8 @@ using namespace std; using namespace tlm; -template class StlPlayer: public TracePlayer +template +class StlPlayer : public TracePlayer { public: StlPlayer(sc_module_name /*name*/, diff --git a/DRAMSys/library/src/simulation/TemperatureController.h b/DRAMSys/library/src/simulation/TemperatureController.h index 3f510d97..8d91d56a 100644 --- a/DRAMSys/library/src/simulation/TemperatureController.h +++ b/DRAMSys/library/src/simulation/TemperatureController.h @@ -43,7 +43,7 @@ #include #include "../common/DebugManager.h" -#include "../common/rename_utils.h" +#include "../common/utils.h" #include "../controller/core/configuration/Configuration.h" #ifdef THERMALSIM diff --git a/DRAMSys/library/src/simulation/TraceGenerator.h b/DRAMSys/library/src/simulation/TraceGenerator.h index 3019b6f5..7a1ebec4 100644 --- a/DRAMSys/library/src/simulation/TraceGenerator.h +++ b/DRAMSys/library/src/simulation/TraceGenerator.h @@ -38,13 +38,13 @@ #ifndef TRACEGENERATOR_H #define TRACEGENERATOR_H - #include "TracePlayer.h" using namespace std; using namespace tlm; -struct TraceGenerator: public TracePlayer { +struct TraceGenerator : public TracePlayer +{ public: TraceGenerator(sc_module_name /*name*/, unsigned int clkMhz, TracePlayerListener *listener) : TracePlayer(listener), transCounter(0) diff --git a/DRAMSys/library/src/simulation/TracePlayer.h b/DRAMSys/library/src/simulation/TracePlayer.h index 5a34df28..fbc2e004 100644 --- a/DRAMSys/library/src/simulation/TracePlayer.h +++ b/DRAMSys/library/src/simulation/TracePlayer.h @@ -56,7 +56,8 @@ using namespace std; using namespace tlm; -struct TracePlayer: public sc_module { +struct TracePlayer : public sc_module +{ public: tlm_utils::simple_initiator_socket iSocket; TracePlayer(TracePlayerListener *listener); diff --git a/DRAMSys/library/src/simulation/TraceSetup.h b/DRAMSys/library/src/simulation/TraceSetup.h index c4c39279..49f91049 100644 --- a/DRAMSys/library/src/simulation/TraceSetup.h +++ b/DRAMSys/library/src/simulation/TraceSetup.h @@ -39,7 +39,7 @@ #include #include -#include "../common/rename_utils.h" +#include "../common/utils.h" #include "TracePlayer.h" #include "StlPlayer.h" From 24a8f7f48384b1f73eab36521dc31e87e0adf806 Mon Sep 17 00:00:00 2001 From: Lukas Steiner Date: Thu, 13 Jun 2019 23:41:22 +0200 Subject: [PATCH 81/97] Code refactoring. --- DRAMSys/library/src/controller/Controller.cpp | 110 ++++++++++-------- DRAMSys/library/src/controller/Controller.h | 2 +- .../src/controller/core/ControllerCore.cpp | 57 +++++---- .../src/controller/scheduler/FifoStrict.h | 10 +- .../src/controller/scheduler/FrFcfs.cpp | 27 +++-- .../library/src/controller/scheduler/FrFcfs.h | 2 +- 6 files changed, 118 insertions(+), 90 deletions(-) diff --git a/DRAMSys/library/src/controller/Controller.cpp b/DRAMSys/library/src/controller/Controller.cpp index 242bde35..178c7e69 100644 --- a/DRAMSys/library/src/controller/Controller.cpp +++ b/DRAMSys/library/src/controller/Controller.cpp @@ -93,7 +93,8 @@ void Controller::send(const ScheduledCommand &command, tlm_phase phase; - switch (command.getCommand()) { + switch (command.getCommand()) + { //TODO: refactor tlm recorder case Command::Read: phase = BEGIN_RD; @@ -108,9 +109,9 @@ void Controller::send(const ScheduledCommand &command, phase = BEGIN_WRA; break; case Command::AutoRefresh: - if (!Configuration::getInstance().BankwiseLogic) { + if (!Configuration::getInstance().BankwiseLogic) phase = BEGIN_REFA; - } else + else phase = BEGIN_REFB; break; case Command::Activate: @@ -129,39 +130,39 @@ void Controller::send(const ScheduledCommand &command, phase = BEGIN_PRE_ALL; break; case Command::PDNA: - if (!Configuration::getInstance().BankwiseLogic) { + if (!Configuration::getInstance().BankwiseLogic) phase = BEGIN_PDNA; - } else + else phase = BEGIN_PDNAB; break; case Command::PDNAX: - if (!Configuration::getInstance().BankwiseLogic) { + if (!Configuration::getInstance().BankwiseLogic) phase = END_PDNA; - } else + else phase = END_PDNAB; break; case Command::PDNP: - if (!Configuration::getInstance().BankwiseLogic) { + if (!Configuration::getInstance().BankwiseLogic) phase = BEGIN_PDNP; - } else + else phase = BEGIN_PDNPB; break; case Command::PDNPX: - if (!Configuration::getInstance().BankwiseLogic) { + if (!Configuration::getInstance().BankwiseLogic) phase = END_PDNP; - } else + else phase = END_PDNPB; break; case Command::SREF: - if (!Configuration::getInstance().BankwiseLogic) { + if (!Configuration::getInstance().BankwiseLogic) phase = BEGIN_SREF; - } else + else phase = BEGIN_SREFB; break; case Command::SREFX: - if (!Configuration::getInstance().BankwiseLogic) { + if (!Configuration::getInstance().BankwiseLogic) phase = END_SREF; - } else + else phase = END_SREFB; break; default: @@ -200,18 +201,23 @@ void Controller::send(Trigger trigger, sc_time time, void Controller::controllerCorePEQCallback(tlm_generic_payload &payload, const tlm_phase &phase) { - if (phase == REF_TRIGGER) { + if (phase == REF_TRIGGER) + { controllerCore->triggerRefresh(payload); - } else if (phase == PDN_TRIGGER) { + } + else if (phase == PDN_TRIGGER) + { controllerCore->powerDownManager->sleep(DramExtension::getExtension( payload).getBank(), sc_time_stamp()); - } else { + } + else + { Bank bank = DramExtension::getBank(payload); sendToDram(payload, phase, SC_ZERO_TIME); - if (phase == BEGIN_RD || phase == BEGIN_WR) { + if (phase == BEGIN_RD || phase == BEGIN_WR) scheduleNextFromScheduler(DramExtension::getBank(payload)); - } else if (phase == BEGIN_REFB) + else if (phase == BEGIN_REFB) printDebugMessage("Entering REFB on bank " + to_string(bank.ID())); else if (phase == BEGIN_REFA) printDebugMessage("Entering REFA"); @@ -242,20 +248,20 @@ tlm_sync_enum Controller::nb_transport_fw(tlm_generic_payload &payload, { sc_time notDelay = fwDelay; - if (phase == BEGIN_REQ) { + if (phase == BEGIN_REQ) + { notDelay += Configuration::getInstance().memSpec.clk; // Bandwidth IDLE - if ((getTotalNumberOfPayloadsInSystem() == 0) && idleState) { + if ((getTotalNumberOfPayloadsInSystem() == 0) && idleState) endBandwidthIdleCollector(); - } } - else if (phase == END_RESP) { + else if (phase == END_RESP) + { // Bandwidth IDLE // TODO: getTotalNumberOfPayloadsInSystem() == 1 && !idleState ?? - if (getTotalNumberOfPayloadsInSystem() == 1) { + if (getTotalNumberOfPayloadsInSystem() == 1) startBandwidthIdleCollector(); - } } printDebugMessage("[fw] " + phaseNameToString(phase) + " notification in " + @@ -275,24 +281,26 @@ void Controller::frontendPEQCallback(tlm_generic_payload &payload, { if (phase == BEGIN_REQ) { - printDebugMessage(string("Payload in system: ") + + printDebugMessage(string("Payloads in system: ") + to_string(getTotalNumberOfPayloadsInSystem())); payload.acquire(); payloadEntersSystem(payload); + // TODO: Different queues: Fifo: queue per bank, FifoStrict: queue per channel if (getTotalNumberOfPayloadsInSystem() > controllerCore->config.MaxNrOfTransactions) { printDebugMessage("##Backpressure: Max number of transactions in system reached"); backpressure = &payload; - return; } - payload.set_response_status(tlm::TLM_OK_RESPONSE); - // tSocket->nb_transport_bw(*backpressure, END_REQ, SC_ZERO_TIME) - sendToFrontend(payload, END_REQ, SC_ZERO_TIME); + else + { + payload.set_response_status(tlm::TLM_OK_RESPONSE); + sendToFrontend(payload, END_REQ, SC_ZERO_TIME); + // tSocket->nb_transport_bw(*backpressure, END_REQ, SC_ZERO_TIME) - scheduler->storeRequest(&payload); - // TODO: (current position in code) - scheduleNextFromScheduler(DramExtension::getExtension(payload).getBank()); + scheduler->storeRequest(&payload); + scheduleNextFromScheduler(DramExtension::getExtension(payload).getBank()); + } } else if (phase == PendingRequest) { @@ -330,15 +338,14 @@ void Controller::frontendPEQCallback(tlm_generic_payload &payload, void Controller::payloadEntersSystem(tlm_generic_payload &payload) { Bank bank = DramExtension::getExtension(payload).getBank(); - // TODO: first increase numberOfPayloadsInSystem[bank], then printDebugMessage ?? + numberOfPayloadsInSystem[bank]++; printDebugMessage( "Payload enters system on bank " + to_string(bank.ID()) + ". Total number of payloads in Controller: " + to_string(getTotalNumberOfPayloadsInSystem())); - numberOfPayloadsInSystem[bank]++; // Set Start Time for Simulation - // TODO: startTimeSet always false at this point?? - if (startTimeSet == false) { + if (!startTimeSet) + { printDebugMessage("Simulation Timer Start"); startTime = sc_time_stamp() - Configuration::getInstance().memSpec.clk; startTimeSet = true; @@ -359,9 +366,8 @@ void Controller::payloadLeavesSystem(tlm_generic_payload &payload) unsigned int Controller::getTotalNumberOfPayloadsInSystem() { unsigned int sum = 0; - for (Bank bank : controllerCore->getBanks()) { + for (Bank bank : controllerCore->getBanks()) sum += numberOfPayloadsInSystem[bank]; - } return sum; } @@ -374,7 +380,8 @@ void Controller::scheduleNextFromScheduler(Bank bank) bool rescheduled = true; pair nextRequest = scheduler->getNextRequest(bank); - if (nextRequest.second != NULL) { + if (nextRequest.second != NULL) + { schedule(nextRequest.first, *nextRequest.second); } else @@ -398,19 +405,27 @@ void Controller::scheduleNextFromScheduler(Bank bank) pair nextRequest = scheduler->getNextRequest(bank); - if (nextRequest.second != NULL) { + if (nextRequest.second != NULL) + { schedule(nextRequest.first, *nextRequest.second); - } else { + } + else + { gp *pendingRequest = scheduler->getPendingRequest(bank); - if (pendingRequest != NULL) { + if (pendingRequest != NULL) + { //Pending request - if (!rescheduled) { + if (!rescheduled) + { // TODO: never reached, rescheduled is always true rescheduled = true; frontendPEQ.notify(*(pendingRequest), PendingRequest, Configuration::getInstance().memSpec.clk); - } else + } + else + { blocked.push(bank); + } } } } @@ -421,7 +436,8 @@ void Controller::schedule(Command command, gp &payload) { controllerCore->powerDownManager->wakeUp(DramExtension::getBank(payload), sc_time_stamp()); - if (controllerCore->scheduleRequest(command, payload)) { + if (controllerCore->scheduleRequest(command, payload)) + { printDebugMessage("\t-> Next payload was scheduled by core [" + commandToString( command) + "] (unblocked)"); } diff --git a/DRAMSys/library/src/controller/Controller.h b/DRAMSys/library/src/controller/Controller.h index 133f10f9..d3d5490b 100644 --- a/DRAMSys/library/src/controller/Controller.h +++ b/DRAMSys/library/src/controller/Controller.h @@ -160,7 +160,7 @@ protected: sc_time idleTime; sc_time endTime; sc_time startTime; - int startTimeSet = false; + bool startTimeSet = false; void startBandwidthIdleCollector(); void endBandwidthIdleCollector(); diff --git a/DRAMSys/library/src/controller/core/ControllerCore.cpp b/DRAMSys/library/src/controller/core/ControllerCore.cpp index f966c965..654d0333 100644 --- a/DRAMSys/library/src/controller/core/ControllerCore.cpp +++ b/DRAMSys/library/src/controller/core/ControllerCore.cpp @@ -138,27 +138,27 @@ ControllerCore::~ControllerCore() void ControllerCore::triggerRefresh(tlm::tlm_generic_payload &payload) { /* Refresh can be disabled for tests purpose */ - if (config.ControllerCoreRefDisable == false) { + if (config.ControllerCoreRefDisable == false) + { sc_time time = sc_time_stamp(); Bank bank = DramExtension::getExtension(payload).getBank(); state->cleanUp(time); if (!refreshManager->isInvalidated(payload, time) - && !powerDownManager->isInSelfRefresh(bank)) { + && !powerDownManager->isInSelfRefresh(bank)) + { printDebugMessage("Triggering refresh on bank " + to_string(bank.ID())); powerDownManager->wakeUpForRefresh(bank, time); //expects PDNA and PDNP to exit without delay bool pdnpToSrefTransition = false; - if (config.PowerDownMode == EPowerDownMode::Staggered) { - pdnpToSrefTransition = state->getLastCommand(Command::PDNPX, - bank).getStart() >= time; - } - if (pdnpToSrefTransition) { + if (config.PowerDownMode == EPowerDownMode::Staggered) + pdnpToSrefTransition = (state->getLastCommand(Command::PDNPX, + bank).getStart() >= time); + if (pdnpToSrefTransition) powerDownManager->sleep(bank, time); - } else { + else refreshManager->scheduleRefresh(payload, time); - } } } } @@ -169,13 +169,17 @@ bool ControllerCore::scheduleRequest(Command command, sc_time start = clkAlign(sc_time_stamp()); state->cleanUp(start); ScheduledCommand scheduledCommand = schedule(command, start, payload); - if (config.ControllerCoreRefDisable) { + if (config.ControllerCoreRefDisable) + { state->change(scheduledCommand); controller.send(scheduledCommand, payload); return true; - } else { + } + else + { if (!((command == Command::Precharge || command == Command::Activate) - && refreshManager->hasCollision(scheduledCommand))) { + && refreshManager->hasCollision(scheduledCommand))) + { state->change(scheduledCommand); controller.send(scheduledCommand, payload); return true; @@ -189,17 +193,17 @@ ScheduledCommand ControllerCore::schedule(Command command, sc_time start, { ControllerCore::printDebugMessage("Scheduling command " + commandToString( command) + " on " + DramExtension::getBank(payload).toString()); - ICommandChecker &checker = getCommandChecker(command); sc_time executionTime = getExecutionTime(command, payload); ScheduledCommand scheduledCommand(command, start, executionTime, DramExtension::getExtension(payload)); - checker.delayToSatisfyConstraints(scheduledCommand); + getCommandChecker(command).delayToSatisfyConstraints(scheduledCommand); return scheduledCommand; } bool ControllerCore::hasPendingRequests() { - for (Bank bank : getBanks()) { + for (Bank bank : getBanks()) + { if (numberOfPayloads[bank] != 0) return true; } @@ -217,22 +221,31 @@ bool ControllerCore::bankIsBusy(Bank bank) ScheduledCommand lastScheduledCommand = state->getLastScheduledCommand(bank); if (lastScheduledCommand.isNoCommand()) + { return false; - else if (lastScheduledCommand.commandIsIn( { Command::Write, Command::Read })) { + } + else if (lastScheduledCommand.commandIsIn({Command::Write, Command::Read})) + { // Read and writes can overlap, so the bank should not be busy during a rd/wr return (time < lastScheduledCommand.getStart()); } - else if (lastScheduledCommand.commandIsIn( { Command::WriteA, Command::ReadA, Command::PreB, Command::Precharge, Command::PrechargeAll, Command::ActB, Command::Activate })) { + else if (lastScheduledCommand.commandIsIn({Command::WriteA, Command::ReadA, Command::PreB, + Command::Precharge, Command::PrechargeAll, + Command::ActB, Command::Activate})) + { return (time < lastScheduledCommand.getEnd()); } - else if (lastScheduledCommand.getCommand() == Command::AutoRefresh) { + else if (lastScheduledCommand.getCommand() == Command::AutoRefresh) + { return (time < lastScheduledCommand.getEnd()); - } else if (lastScheduledCommand.commandIsIn( { Command::SREFX, Command::PDNPX, Command::PDNAX, Command::SREF, Command::PDNP, - Command::PDNA - })) { + } + else if (lastScheduledCommand.commandIsIn({Command::SREFX, Command::PDNPX, Command::PDNAX, + Command::SREF, Command::PDNP, Command::PDNA})) + { return false; } - else { + else + { SC_REPORT_FATAL("Core", "Last command unkown"); return false; } diff --git a/DRAMSys/library/src/controller/scheduler/FifoStrict.h b/DRAMSys/library/src/controller/scheduler/FifoStrict.h index 2cf8c3dd..5404cb8c 100644 --- a/DRAMSys/library/src/controller/scheduler/FifoStrict.h +++ b/DRAMSys/library/src/controller/scheduler/FifoStrict.h @@ -51,14 +51,14 @@ class FifoStrict : public IScheduler { public: IController &controller; - FifoStrict(IController &controller, - ControllerCore &controllerCore) : IScheduler(controllerCore), - controller(controller) {} + FifoStrict(IController &controller, ControllerCore &controllerCore) + : IScheduler(controllerCore), controller(controller) {} + virtual ~FifoStrict() {} void storeRequest(gp *payload) override; - std::pair getNextRequest( - Bank bank) override; + std::pair + getNextRequest(Bank bank) override; virtual gp *getPendingRequest(Bank bank) override; private: diff --git a/DRAMSys/library/src/controller/scheduler/FrFcfs.cpp b/DRAMSys/library/src/controller/scheduler/FrFcfs.cpp index 6aefbe29..afa12aa2 100644 --- a/DRAMSys/library/src/controller/scheduler/FrFcfs.cpp +++ b/DRAMSys/library/src/controller/scheduler/FrFcfs.cpp @@ -70,23 +70,23 @@ void FrFcfs::storeRequest(gp *payload) std::pair FrFcfs::getNextRequest(Bank bank) { // If the bank is empty like Bank0 in the example we do nothing - if (buffer[bank].empty()) { - return pair(Command::NOP, NULL); - } + if (buffer[bank].empty()) + return std::pair(Command::NOP, NULL); // In FR_FCFS row hits have always the highest priority, therefore we search // for row hits. If we find a row hit, we remove the transaction from the // queue and send it to the DRAM. - deque::iterator it = FindRowHit(bank); - if (it != buffer[bank].end()) { + std::deque::iterator it = findRowHit(bank); + if (it != buffer[bank].end()) + { gp *payload = *it; buffer[bank].erase(it); - return pair(getReadWriteCommand(payload), payload); + return std::pair(getReadWriteCommand(payload), payload); } // If there is no row hit, the FR_FCFS takes always the oldest transaction // in the buffer, i.e. the transaction in the front. - return pair(getNextCommand(buffer[bank].front()), + return std::pair(getNextCommand(buffer[bank].front()), buffer[bank].front()); } @@ -97,21 +97,20 @@ std::pair FrFcfs::getNextRequest(Bank bank) // deque container. The past-the-end element is the theoretical element that // would follow the last element in the deque container. It does not point to // any element, and thus shall not be dereferenced. -deque::iterator FrFcfs::FindRowHit(Bank bank) +std::deque::iterator FrFcfs::findRowHit(Bank bank) { - deque &queue = buffer[bank]; + std::deque &queue = buffer[bank]; + Row activeRow = controllerCore.getRowBufferStates().getRowInRowBuffer(bank); if (!controllerCore.getRowBufferStates().rowBufferIsOpen(bank)) return queue.end(); // Traverse the scheduling queue of the specific bank: - for (auto it = queue.begin(); it != queue.end(); it++) { - gp *payload = *it; + for (auto it = queue.begin(); it != queue.end(); it++) + { //Found row-hit and return the according iterator - if (DramExtension::getRow(payload) - == controllerCore.getRowBufferStates().getRowInRowBuffer(bank)) { + if (DramExtension::getRow(*it) == activeRow) return it; - } } return queue.end(); diff --git a/DRAMSys/library/src/controller/scheduler/FrFcfs.h b/DRAMSys/library/src/controller/scheduler/FrFcfs.h index 92fd34f3..b3fa643b 100644 --- a/DRAMSys/library/src/controller/scheduler/FrFcfs.h +++ b/DRAMSys/library/src/controller/scheduler/FrFcfs.h @@ -57,7 +57,7 @@ public: protected: std::map> buffer; - std::deque::iterator FindRowHit(Bank bank); + std::deque::iterator findRowHit(Bank bank); private: From bf1a9dc47d6319d8fe0d777cbae335da60eb9ee1 Mon Sep 17 00:00:00 2001 From: Lukas Steiner Date: Sun, 16 Jun 2019 21:12:33 +0200 Subject: [PATCH 82/97] Moved bandwidth calculation from Dram to Controller. --- DRAMSys/library/src/controller/Controller.cpp | 49 +++++++++++++ DRAMSys/library/src/controller/Controller.h | 7 +- DRAMSys/library/src/simulation/DRAMSys.cpp | 1 - DRAMSys/library/src/simulation/Dram.h | 70 ------------------- 4 files changed, 51 insertions(+), 76 deletions(-) diff --git a/DRAMSys/library/src/controller/Controller.cpp b/DRAMSys/library/src/controller/Controller.cpp index ebe31027..cadb12e1 100644 --- a/DRAMSys/library/src/controller/Controller.cpp +++ b/DRAMSys/library/src/controller/Controller.cpp @@ -39,6 +39,53 @@ #include "Controller.h" #include +Controller::~Controller() +{ + // Bandwidth: + sc_time activeTime = numberOfTransactionsServed + * Configuration::getInstance().memSpec.BurstLength + / Configuration::getInstance().memSpec.DataRate + * Configuration::getInstance().memSpec.clk; + + sc_time idleTime = getIdleTime(); + sc_time endTime = getEndTime(); + sc_time startTime = getStartTime(); + + double bandwidth = (activeTime / (endTime - startTime) * 100); + double bandwidth_IDLE = ((activeTime) / (endTime - startTime - idleTime) * 100); + + double maxBandwidth = ( + // clk in Mhz e.g. 800 [MHz]: + (1000000 / Configuration::getInstance().memSpec.clk.to_double()) + // DataRate e.g. 2 + * Configuration::getInstance().memSpec.DataRate + // BusWidth e.g. 8 or 64 + * Configuration::getInstance().memSpec.bitWidth + // Number of devices on a DIMM e.g. 8 + * Configuration::getInstance().NumberOfDevicesOnDIMM ) / ( 1024 ); + + cout << name() << string(" Total Time: ") + << (endTime - startTime).to_string() + << endl; + cout << name() << string(" AVG BW: ") + << std::fixed << std::setprecision(2) + << ((bandwidth / 100)*maxBandwidth) + << " Gibit/s (" << bandwidth << " %)" + << endl; + cout << name() << string(" AVG BW/IDLE: ") + << std::fixed << std::setprecision(2) + << ((bandwidth_IDLE / 100)*maxBandwidth) + << " Gibit/s (" << (bandwidth_IDLE) << " %)" + << endl; + cout << name() << string(" MAX BW: ") + << std::fixed << std::setprecision(2) + << maxBandwidth << " Gibit/s" + << endl; + + delete controllerCore; + delete scheduler; +} + void Controller::buildScheduler() { string selectedScheduler = Configuration::getInstance().Scheduler; @@ -470,6 +517,8 @@ void Controller::sendToDram(tlm_generic_payload &payload, { tlm_phase TPhase = phase; sc_time TDelay = delay; + if (phase == BEGIN_WR || phase == BEGIN_RD || phase == BEGIN_WRA || phase == BEGIN_RDA) + numberOfTransactionsServed++; iSocket->nb_transport_fw(payload, TPhase, TDelay); } diff --git a/DRAMSys/library/src/controller/Controller.h b/DRAMSys/library/src/controller/Controller.h index c309c02d..89bc46c2 100644 --- a/DRAMSys/library/src/controller/Controller.h +++ b/DRAMSys/library/src/controller/Controller.h @@ -94,11 +94,7 @@ public: tSocket.register_transport_dbg(this, &Controller::transport_dbg); } - virtual ~Controller() - { - delete controllerCore; - delete scheduler; - } + virtual ~Controller(); void terminateSimulation(); @@ -172,6 +168,7 @@ protected: sc_time endTime; sc_time startTime; int startTimeSet = false; + unsigned long long int numberOfTransactionsServed = 0; void startBandwidthIdleCollector(); void endBandwidthIdleCollector(); diff --git a/DRAMSys/library/src/simulation/DRAMSys.cpp b/DRAMSys/library/src/simulation/DRAMSys.cpp index 5b48fc92..2ceb61b3 100644 --- a/DRAMSys/library/src/simulation/DRAMSys.cpp +++ b/DRAMSys/library/src/simulation/DRAMSys.cpp @@ -260,7 +260,6 @@ void DRAMSys::instantiateModules(const string &traceName, dram = new RecordableDram(str.c_str(), tlmRecorders[i]); else dram = new Dram(str.c_str()); - dram->setDramController(controllers[i]); drams.push_back(dram); if (Configuration::getInstance().CheckTLM2Protocol) { diff --git a/DRAMSys/library/src/simulation/Dram.h b/DRAMSys/library/src/simulation/Dram.h index 7c383498..0068e83b 100644 --- a/DRAMSys/library/src/simulation/Dram.h +++ b/DRAMSys/library/src/simulation/Dram.h @@ -74,11 +74,6 @@ struct Dram : sc_module { bool powerAnalysis = Configuration::getInstance().PowerAnalysis; libDRAMPower *DRAMPower; - // Bandwidth realted: - unsigned long long int numberOfTransactionsServed; - sc_time firstAccess; - sc_time lastAccess; - // Error Model related: StorageMode StoreMode = Configuration::getInstance().StoreMode; std::vector ememory; @@ -86,14 +81,11 @@ struct Dram : sc_module { // Data Storage: unsigned char *memory; - Controller *dramController; - SC_CTOR(Dram) : tSocket("socket") { // Adjust number of bytes per burst dynamically to the selected ecc controller bytesPerBurst = Configuration::getInstance().adjustNumBytesAfterECC( bytesPerBurst); - dramController = NULL; std::uint64_t memorySize = Configuration::getInstance().getSimMemSizeInBytes(); if (Configuration::getInstance().UseMalloc) { @@ -214,11 +206,6 @@ struct Dram : sc_module { DRAMPower = new libDRAMPower( memSpec, 0 ); } - // Bandwidth Calculation: - numberOfTransactionsServed = 0; - firstAccess = SC_ZERO_TIME; - lastAccess = SC_ZERO_TIME; - // For each bank in a channel a error Model is created: if (StoreMode == StorageMode::ErrorModel) { for (unsigned i = 0; i < Configuration::getInstance().memSpec.NumberOfBanks; @@ -261,47 +248,6 @@ struct Dram : sc_module { << string(" mW") << endl; } - // Bandwidth: - - sc_time activeTime = numberOfTransactionsServed - * Configuration::getInstance().memSpec.BurstLength - / Configuration::getInstance().memSpec.DataRate - * Configuration::getInstance().memSpec.clk; - - sc_time idleTime = dramController->getIdleTime(); - sc_time endTime = dramController->getEndTime(); - sc_time startTime = dramController->getStartTime(); - - double bandwidth = (activeTime / (endTime - startTime) * 100); - double bandwidth_IDLE = ((activeTime) / (endTime - startTime - idleTime) * 100); - - double maxBandwidth = ( - // clk in Mhz e.g. 800 [MHz]: - (1000000 / Configuration::getInstance().memSpec.clk.to_double()) - // DataRate e.g. 2 - * Configuration::getInstance().memSpec.DataRate - // BusWidth e.g. 8 or 64 - * Configuration::getInstance().memSpec.bitWidth - // Number of devices on a DIMM e.g. 8 - * Configuration::getInstance().NumberOfDevicesOnDIMM ) / ( 1024 ); - - cout << name() << string(" Total Time: ") - << (endTime - startTime).to_string() - << endl; - cout << name() << string(" AVG BW: ") - << std::fixed << std::setprecision(2) - << ((bandwidth / 100)*maxBandwidth) - << " Gibit/s (" << bandwidth << " %)" - << endl; - cout << name() << string(" AVG BW/IDLE: ") - << std::fixed << std::setprecision(2) - << ((bandwidth_IDLE / 100)*maxBandwidth) - << " Gibit/s (" << (bandwidth_IDLE) << " %)" - << endl; - cout << name() << string(" MAX BW: ") - << std::fixed << std::setprecision(2) - << maxBandwidth << " Gibit/s" - << endl; // Clean up: for (auto e : ememory) { delete e; @@ -315,12 +261,6 @@ struct Dram : sc_module { virtual tlm::tlm_sync_enum nb_transport_fw(tlm::tlm_generic_payload &payload, tlm::tlm_phase &phase, sc_time &delay) { - if (numberOfTransactionsServed == 0) { - firstAccess = sc_time_stamp(); - } else { - lastAccess = sc_time_stamp(); - } - unsigned int bank = DramExtension::getExtension(payload).getBank().ID(); // This is only needed for power simulation: @@ -376,7 +316,6 @@ struct Dram : sc_module { if (powerAnalysis == true) { DRAMPower->doCommand(MemCommand::WR, bank, cycle); } - numberOfTransactionsServed++; //save data: if (StoreMode == StorageMode::NoStorage) { @@ -393,8 +332,6 @@ struct Dram : sc_module { #if !defined (DRAMSYS_PCT) && !defined (DRAMSYS_GEM5) assert(payload.get_data_length() == bytesPerBurst); #endif - - numberOfTransactionsServed++; if (powerAnalysis == true) { DRAMPower->doCommand(MemCommand::RD, bank, cycle); } @@ -411,7 +348,6 @@ struct Dram : sc_module { sendToController(payload, END_RD, delay + getExecutionTime(Command::Read, payload)); } else if (phase == BEGIN_WRA) { - numberOfTransactionsServed++; if (powerAnalysis == true) { DRAMPower->doCommand(MemCommand::WRA, bank, cycle); } @@ -428,7 +364,6 @@ struct Dram : sc_module { sendToController(payload, END_WRA, delay + getExecutionTime(Command::WriteA, payload)); } else if (phase == BEGIN_RDA) { - numberOfTransactionsServed++; if (powerAnalysis == true) { DRAMPower->doCommand(MemCommand::RDA, bank, cycle); } @@ -576,11 +511,6 @@ struct Dram : sc_module { { DebugManager::getInstance().printDebugMessage(name(), message); } - - void setDramController(Controller *contr) - { - dramController = contr; - } }; #endif /* DRAM_H_ */ From a97a20b148eedbbd872198c1bd2bf1d0214d1432 Mon Sep 17 00:00:00 2001 From: "Lukas Steiner (2)" Date: Mon, 17 Jun 2019 17:41:46 +0200 Subject: [PATCH 83/97] Added specific MemSpecs, commit not running! --- .../src/controller/core/ControllerCore.cpp | 3 + .../configuration/ConfigurationLoader.cpp | 70 +++++++++++-------- .../controller/core/configuration/MemSpec.h | 66 +++++++++++++---- 3 files changed, 96 insertions(+), 43 deletions(-) diff --git a/DRAMSys/library/src/controller/core/ControllerCore.cpp b/DRAMSys/library/src/controller/core/ControllerCore.cpp index 654d0333..b1c801a7 100644 --- a/DRAMSys/library/src/controller/core/ControllerCore.cpp +++ b/DRAMSys/library/src/controller/core/ControllerCore.cpp @@ -87,6 +87,8 @@ ControllerCore::ControllerCore(sc_module_name /*name*/, if (config.RowGranularRef) { refreshManager = new RGR("RGR", *this); + // TODO: How to use asserts with new memspec? + /* assert(config.getTrasb() <= config.memSpec.tRAS); assert(config.getTrasb() >= config.memSpec.tRCD); assert(config.getTrrdb_L() <= config.memSpec.tRRD_L); @@ -94,6 +96,7 @@ ControllerCore::ControllerCore(sc_module_name /*name*/, assert(config.getTrpb() <= config.memSpec.tRP); assert(config.getTrcb() <= config.memSpec.tRC); assert(config.getTfawb() <= config.memSpec.tNAW); + */ } else { if (config.BankwiseLogic) { refreshManager = new RefreshManagerBankwise("refManagerBw", *this); diff --git a/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.cpp b/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.cpp index a8fb37c8..093479c8 100644 --- a/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.cpp +++ b/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.cpp @@ -101,34 +101,6 @@ void ConfigurationLoader::loadConfigFromUri(Configuration &config, loadConfig(config, e); } -void ConfigurationLoader::loadMemSpec(Configuration &config, string memspecUri) -{ - tinyxml2::XMLDocument doc; - config.memspecUri = memspecUri; - loadXML(memspecUri, doc); - XMLElement *memspec = doc.FirstChildElement("memspec"); - loadMemSpec(config, memspec); -} - -void ConfigurationLoader::loadMemSpec(Configuration &config, - XMLElement *memspec) -{ - config.memSpec.MemoryId = queryStringParameter(memspec, "memoryId"); - config.memSpec.MemoryType = queryStringParameter(memspec, "memoryType"); - - if (config.memSpec.MemoryType == "DDR4") { - loadDDR4(config, memspec); - } else if (config.memSpec.MemoryType == "DDR3") { - loadDDR3(config, memspec); - } else if (config.memSpec.MemoryType == "LPDDR4") { - loadLPDDR4(config, memspec); - } else if (config.memSpec.MemoryType == "WIDEIO_SDR") { - loadWideIO(config, memspec); - } else { - reportFatal("ConfigurationLoader", "Unsupported DRAM type"); - } -} - void ConfigurationLoader::loadMCConfig(Configuration &config, string mcconfigUri) { @@ -155,6 +127,48 @@ void ConfigurationLoader::loadMCConfig(Configuration &config, } +void ConfigurationLoader::loadMemSpec(Configuration &config, string memspecUri) +{ + tinyxml2::XMLDocument doc; + config.memspecUri = memspecUri; + loadXML(memspecUri, doc); + XMLElement *memspec = doc.FirstChildElement("memspec"); + loadMemSpec(config, memspec); +} + +void ConfigurationLoader::loadMemSpec(Configuration &config, + XMLElement *memspec) +{ + config.memSpec.MemoryId = queryStringParameter(memspec, "memoryId"); + config.memSpec.MemoryType = queryStringParameter(memspec, "memoryType"); + + std::cout << "Before" << std::endl; + if (config.memSpec.MemoryType == "DDR4") { + delete(&Configuration::getInstance().memSpec); + Configuration::getInstance().memSpec = + *new MemSpecDDR4; + loadDDR4(config, memspec); + } else if (config.memSpec.MemoryType == "DDR3") { + delete(&Configuration::getInstance().memSpec); + Configuration::getInstance().memSpec = + *new MemSpecDDR3; + loadDDR3(config, memspec); + } else if (config.memSpec.MemoryType == "LPDDR4") { + delete(&Configuration::getInstance().memSpec); + Configuration::getInstance().memSpec = + *new MemSpecLPDDR4; + loadLPDDR4(config, memspec); + } else if (config.memSpec.MemoryType == "WIDEIO_SDR") { + delete(&Configuration::getInstance().memSpec); + Configuration::getInstance().memSpec = + *new MemSpecWideIO; + loadWideIO(config, memspec); + } else { + reportFatal("ConfigurationLoader", "Unsupported DRAM type"); + } + std::cout << "After" << std::endl; +} + void ConfigurationLoader::loadDDR3(Configuration &config, XMLElement *memspec) { //MemArchitecture diff --git a/DRAMSys/library/src/controller/core/configuration/MemSpec.h b/DRAMSys/library/src/controller/core/configuration/MemSpec.h index 9a5e06d5..00a48073 100644 --- a/DRAMSys/library/src/controller/core/configuration/MemSpec.h +++ b/DRAMSys/library/src/controller/core/configuration/MemSpec.h @@ -41,7 +41,8 @@ #include #include "../../../common/dramExtensions.h" -struct RefreshTiming { +struct RefreshTiming +{ RefreshTiming() {} RefreshTiming(sc_time tRFC, sc_time tREFI) : tRFC(tRFC), tRFC2(SC_ZERO_TIME), tRFC4(SC_ZERO_TIME), tREFI(tREFI) {} @@ -53,7 +54,8 @@ struct RefreshTiming { sc_time tREFI; }; -struct MemSpec { +struct MemSpec +{ MemSpec() { //default DDR4 @@ -89,24 +91,31 @@ struct MemSpec { // Memspec Variables: double clkMHz; sc_time clk; - sc_time tRP; //precharge-time (pre -> act same bank) + sc_time tRP; //precharge-time (pre -> act same bank + sc_time tRTP; //Read to precharge + sc_time tRCD; //act -> read/write + sc_time tRL; //read latency (read command start to data strobe) + sc_time tWL; //write latency + sc_time tWR; //write recovery (write to precharge) + sc_time tCKESR; //min time in sref + sc_time tCKE; //min time in pdna or pdnp + + sc_time tRFC; //min ref->act delay 1X mode + sc_time tRFC2; //min ref->act delay 2X mode + sc_time tRFC4; //min ref->act delay 4X mode + sc_time tREFI; //auto refresh must be issued at an average periodic interval tREFI + + // TODO: move to specific memspecs sc_time tRPAB; //precharge-all time only for LPDDR4 sc_time tRAS; //active-time (act -> pre same bank) sc_time tRC; //RAS-cycle-time (min time bw 2 succesive ACT to same bank) sc_time tCCD_S; //max(bl, tCCD) is relevant for rd->rd sc_time tCCD_L; - sc_time tRTP; //Read to precharge sc_time tRRD_S; //min time bw 2 succesive ACT to different banks (different bank group) sc_time tRRD_L; //.. (same bank group) - sc_time tRCD; //act -> read/write sc_time tNAW; //n activate window - sc_time tRL; //read latency (read command start to data strobe) - sc_time tWL; //write latency - sc_time tWR; //write recovery (write to precharge) sc_time tWTR_S; //write to read (different bank group) sc_time tWTR_L; //.. (same bank group) - sc_time tCKESR; //min time in sref - sc_time tCKE; //min time in pdna or pdnp sc_time tXP; //min delay to row access command after pdnpx pdnax sc_time tXPDLL; //min delay to row access command after pdnpx pdnax for dll commands sc_time tXSR; //min delay to row access command after srefx @@ -114,11 +123,6 @@ struct MemSpec { sc_time tAL; //additive delay (delayed execution in dram) sc_time tDQSCK; - sc_time tRFC; //min ref->act delay 1X mode - sc_time tRFC2; //min ref->act delay 2X mode - sc_time tRFC4; //min ref->act delay 4X mode - sc_time tREFI; //auto refresh must be issued at an average periodic interval tREFI - // Currents and Voltages: double iDD0; double iDD02; @@ -164,5 +168,37 @@ struct MemSpec { } }; +struct MemSpecDDR3 : public MemSpec +{ + MemSpecDDR3() + { + std::cout << "Generated MemSpecDDR3" << std::endl; + } +}; + +struct MemSpecDDR4 : public MemSpec +{ + MemSpecDDR4() + { + std::cout << "Generated MemSpecDDR4" << std::endl; + } +}; + +struct MemSpecWideIO : public MemSpec +{ + MemSpecWideIO() + { + std::cout << "Generated MemSpecWideIO" << std::endl; + } +}; + +struct MemSpecLPDDR4 : public MemSpec +{ + MemSpecLPDDR4() + { + std::cout << "Generated MemSpecLPDDR4" << std::endl; + } +}; + #endif // MEMSPEC_H From 7540388cfe33794426b2071d7d677686f03b2928 Mon Sep 17 00:00:00 2001 From: Lukas Steiner Date: Mon, 17 Jun 2019 19:31:21 +0200 Subject: [PATCH 84/97] Preparation for specific memspecs (member memSpec is now dynamic). --- DRAMSys/library/src/common/TlmRecorder.cpp | 6 +- .../library/src/common/XmlAddressDecoder.cpp | 4 +- DRAMSys/library/src/common/dramExtensions.cpp | 2 +- DRAMSys/library/src/controller/Controller.cpp | 10 +- .../src/controller/ControllerState.cpp | 14 +- .../library/src/controller/ControllerState.h | 2 +- .../src/controller/RowBufferStates.cpp | 4 +- .../src/controller/core/ControllerCore.cpp | 16 +- .../core/configuration/Configuration.cpp | 26 +- .../core/configuration/Configuration.h | 4 +- .../configuration/ConfigurationLoader.cpp | 528 +++++++++--------- .../core/configuration/ConfigurationLoader.h | 5 +- .../controller/core/configuration/MemSpec.h | 25 +- .../src/controller/core/refresh/RGR.cpp | 8 +- .../core/refresh/RefreshManager.cpp | 8 +- .../core/refresh/RefreshManagerBankwise.cpp | 8 +- .../core/scheduling/ScheduledCommand.cpp | 10 +- .../core/scheduling/checker/ActBChecker.cpp | 30 +- .../scheduling/checker/ActivateChecker.cpp | 32 +- .../scheduling/checker/PowerDownChecker.cpp | 26 +- .../core/scheduling/checker/PreBChecker.cpp | 18 +- .../checker/PrechargeAllChecker.cpp | 28 +- .../scheduling/checker/PrechargeChecker.cpp | 12 +- .../core/scheduling/checker/ReadChecker.cpp | 20 +- .../scheduling/checker/RefreshChecker.cpp | 28 +- .../core/scheduling/checker/WriteChecker.cpp | 14 +- .../controller/core/timingCalculations.cpp | 46 +- .../src/controller/scheduler/FrFcfsGrp.cpp | 4 +- .../library/src/controller/scheduler/Grp.cpp | 4 +- .../library/src/controller/scheduler/SMS.cpp | 2 +- DRAMSys/library/src/error/errormodel.cpp | 10 +- DRAMSys/library/src/simulation/Arbiter.cpp | 2 +- DRAMSys/library/src/simulation/Dram.cpp | 156 +++--- .../library/src/simulation/RecordableDram.cpp | 2 +- .../library/src/simulation/RecordableDram.h | 2 +- DRAMSys/library/src/simulation/StlPlayer.h | 2 +- .../library/src/simulation/TraceGenerator.h | 4 +- 37 files changed, 553 insertions(+), 569 deletions(-) diff --git a/DRAMSys/library/src/common/TlmRecorder.cpp b/DRAMSys/library/src/common/TlmRecorder.cpp index c365c060..8619e3ca 100644 --- a/DRAMSys/library/src/common/TlmRecorder.cpp +++ b/DRAMSys/library/src/common/TlmRecorder.cpp @@ -323,9 +323,9 @@ void TlmRecorder::insertGeneralInfo() sqlite3_bind_int64(insertGeneralInfoStatement, 2, simulationTimeCoveredByRecording.value()); sqlite3_bind_int(insertGeneralInfoStatement, 3, - Configuration::getInstance().memSpec.NumberOfBanks); + Configuration::getInstance().memSpec->NumberOfBanks); sqlite3_bind_int(insertGeneralInfoStatement, 4, - Configuration::getInstance().memSpec.clk.value()); + Configuration::getInstance().memSpec->clk.value()); sqlite3_bind_text(insertGeneralInfoStatement, 5, "PS", 2, NULL); sqlite3_bind_text(insertGeneralInfoStatement, 6, mcconfig.c_str(), mcconfig.length(), NULL); @@ -337,7 +337,7 @@ void TlmRecorder::insertGeneralInfo() sqlite3_bind_int64(insertGeneralInfoStatement, 9, 0); else sqlite3_bind_int64(insertGeneralInfoStatement, 9, - (Configuration::getInstance().memSpec.clk * + (Configuration::getInstance().memSpec->clk * Configuration::getInstance().WindowSize).value()); if (Configuration::getInstance().ControllerCoreRefEnablePostpone || Configuration::getInstance().ControllerCoreRefEnablePullIn) { diff --git a/DRAMSys/library/src/common/XmlAddressDecoder.cpp b/DRAMSys/library/src/common/XmlAddressDecoder.cpp index f94011d2..dfbb4dd8 100644 --- a/DRAMSys/library/src/common/XmlAddressDecoder.cpp +++ b/DRAMSys/library/src/common/XmlAddressDecoder.cpp @@ -84,8 +84,8 @@ DecodedAddress XmlAddressDecoder::decodeAddress(sc_dt::uint64 addr) //result.bankgroup = (addr & masks["bankgroup"]) >> shifts["bankgroup"]; result.bank = (addr & masks["bank"]) >> shifts["bank"]; result.bankgroup = result.bank % - Configuration::getInstance().memSpec.NumberOfBankGroups; - result.rank = result.bank % Configuration::getInstance().memSpec.NumberOfRanks; + Configuration::getInstance().memSpec->NumberOfBankGroups; + result.rank = result.bank % Configuration::getInstance().memSpec->NumberOfRanks; result.row = (addr & masks["row"]) >> shifts["row"]; result.column = (addr & masks["column"]) >> shifts["column"]; result.bytes = (addr & masks["bytes"]) >> shifts["bytes"]; diff --git a/DRAMSys/library/src/common/dramExtensions.cpp b/DRAMSys/library/src/common/dramExtensions.cpp index 9a2b9da3..ed1d0b0d 100644 --- a/DRAMSys/library/src/common/dramExtensions.cpp +++ b/DRAMSys/library/src/common/dramExtensions.cpp @@ -281,7 +281,7 @@ bool operator !=(const Row &lhs, const Row &rhs) const Row Row::operator ++() { - id = (id + 1) % Configuration::getInstance().memSpec.NumberOfRows; + id = (id + 1) % Configuration::getInstance().memSpec->NumberOfRows; return *this; } diff --git a/DRAMSys/library/src/controller/Controller.cpp b/DRAMSys/library/src/controller/Controller.cpp index 178c7e69..5e469c8f 100644 --- a/DRAMSys/library/src/controller/Controller.cpp +++ b/DRAMSys/library/src/controller/Controller.cpp @@ -250,7 +250,7 @@ tlm_sync_enum Controller::nb_transport_fw(tlm_generic_payload &payload, if (phase == BEGIN_REQ) { - notDelay += Configuration::getInstance().memSpec.clk; + notDelay += Configuration::getInstance().memSpec->clk; // Bandwidth IDLE if ((getTotalNumberOfPayloadsInSystem() == 0) && idleState) @@ -347,7 +347,7 @@ void Controller::payloadEntersSystem(tlm_generic_payload &payload) if (!startTimeSet) { printDebugMessage("Simulation Timer Start"); - startTime = sc_time_stamp() - Configuration::getInstance().memSpec.clk; + startTime = sc_time_stamp() - Configuration::getInstance().memSpec->clk; startTimeSet = true; } } @@ -392,7 +392,7 @@ void Controller::scheduleNextFromScheduler(Bank bank) { rescheduled = true; frontendPEQ.notify(*(pendingRequest), PendingRequest, - Configuration::getInstance().memSpec.clk); + Configuration::getInstance().memSpec->clk); } } @@ -420,7 +420,7 @@ void Controller::scheduleNextFromScheduler(Bank bank) // TODO: never reached, rescheduled is always true rescheduled = true; frontendPEQ.notify(*(pendingRequest), PendingRequest, - Configuration::getInstance().memSpec.clk); + Configuration::getInstance().memSpec->clk); } else { @@ -579,7 +579,7 @@ void Controller::endBandwidthIdleCollector() { printDebugMessage("IDLE End"); idleTime += sc_time_stamp() - idleStart + - Configuration::getInstance().memSpec.clk; + Configuration::getInstance().memSpec->clk; idleState = false; } diff --git a/DRAMSys/library/src/controller/ControllerState.cpp b/DRAMSys/library/src/controller/ControllerState.cpp index a94905f8..c7318363 100644 --- a/DRAMSys/library/src/controller/ControllerState.cpp +++ b/DRAMSys/library/src/controller/ControllerState.cpp @@ -51,7 +51,7 @@ const ScheduledCommand ControllerState::getLastCommand(Command command) { ScheduledCommand max; - for (unsigned int i = 0; i < config->memSpec.NumberOfBanks; ++i) { + for (unsigned int i = 0; i < config->memSpec->NumberOfBanks; ++i) { ScheduledCommand current = getLastCommand(command, Bank(i)); if (current.getStart() > max.getStart()) max = current; @@ -65,7 +65,7 @@ const ScheduledCommand ControllerState::getLastScheduledCommand() ScheduledCommand lastCommand; for (Command cmd : getAllCommands()) { - for (Bank bank : Configuration::getInstance().memSpec.getBanks()) { + for (Bank bank : Configuration::getInstance().memSpec->getBanks()) { ScheduledCommand ¤t = lastScheduledByCommandAndBank[cmd][bank]; if (current.getStart() > lastCommand.getStart()) lastCommand = current; @@ -154,17 +154,17 @@ void ControllerState::cleanUp(sc_time time) vector tmp; for (ScheduledCommand &command : lastDataStrobeCommands) { if (command.getEnd() >= time - || getDistance(command.getEnd(), time) <= config->memSpec.tDataStrobeHistory()) + || getDistance(command.getEnd(), time) <= config->memSpec->tDataStrobeHistory()) tmp.push_back(command); } lastDataStrobeCommands = tmp; - if (time >= config->memSpec.tActHistory()) + if (time >= config->memSpec->tActHistory()) lastActivates.erase(lastActivates.begin(), - lastActivates.lower_bound(time - config->memSpec.tActHistory())); + lastActivates.lower_bound(time - config->memSpec->tActHistory())); - if (time >= config->memSpec.tActBHistory()) + if (time >= config->memSpec->tActBHistory()) lastActivatesB.erase(lastActivatesB.begin(), - lastActivatesB.lower_bound(time - config->memSpec.tActBHistory())); + lastActivatesB.lower_bound(time - config->memSpec->tActBHistory())); } void ControllerState::printDebugMessage(std::string message) diff --git a/DRAMSys/library/src/controller/ControllerState.h b/DRAMSys/library/src/controller/ControllerState.h index 77b99799..a5d9d609 100644 --- a/DRAMSys/library/src/controller/ControllerState.h +++ b/DRAMSys/library/src/controller/ControllerState.h @@ -49,7 +49,7 @@ class ControllerState { public: ControllerState(std::string ownerName, - Configuration *config) : bus(config->memSpec.clk), ownerName(ownerName), + Configuration *config) : bus(config->memSpec->clk), ownerName(ownerName), config(config) { rowBufferStates = new RowBufferState(ownerName); diff --git a/DRAMSys/library/src/controller/RowBufferStates.cpp b/DRAMSys/library/src/controller/RowBufferStates.cpp index e47f5298..4db36b8a 100644 --- a/DRAMSys/library/src/controller/RowBufferStates.cpp +++ b/DRAMSys/library/src/controller/RowBufferStates.cpp @@ -76,7 +76,7 @@ void RowBufferState::closeRowBuffer(Bank bank) bool RowBufferState::allRowBuffersAreClosed() const { - for (unsigned int i = 0; i < Configuration::getInstance().memSpec.NumberOfBanks; + for (unsigned int i = 0; i < Configuration::getInstance().memSpec->NumberOfBanks; ++i) { if (rowBufferIsOpen(Bank(i))) return false; @@ -86,7 +86,7 @@ bool RowBufferState::allRowBuffersAreClosed() const void RowBufferState::closeAllRowBuffers() { - for (unsigned int i = 0; i < Configuration::getInstance().memSpec.NumberOfBanks; + for (unsigned int i = 0; i < Configuration::getInstance().memSpec->NumberOfBanks; ++i) { rowsInRowBuffers[Bank(i)] = Row::NO_ROW; } diff --git a/DRAMSys/library/src/controller/core/ControllerCore.cpp b/DRAMSys/library/src/controller/core/ControllerCore.cpp index b1c801a7..5c43afcc 100644 --- a/DRAMSys/library/src/controller/core/ControllerCore.cpp +++ b/DRAMSys/library/src/controller/core/ControllerCore.cpp @@ -89,13 +89,13 @@ ControllerCore::ControllerCore(sc_module_name /*name*/, refreshManager = new RGR("RGR", *this); // TODO: How to use asserts with new memspec? /* - assert(config.getTrasb() <= config.memSpec.tRAS); - assert(config.getTrasb() >= config.memSpec.tRCD); - assert(config.getTrrdb_L() <= config.memSpec.tRRD_L); - assert(config.getTrrdb_S() <= config.memSpec.tRRD_S); - assert(config.getTrpb() <= config.memSpec.tRP); - assert(config.getTrcb() <= config.memSpec.tRC); - assert(config.getTfawb() <= config.memSpec.tNAW); + assert(config.getTrasb() <= config.memSpec->tRAS); + assert(config.getTrasb() >= config.memSpec->tRCD); + assert(config.getTrrdb_L() <= config.memSpec->tRRD_L); + assert(config.getTrrdb_S() <= config.memSpec->tRRD_S); + assert(config.getTrpb() <= config.memSpec->tRP); + assert(config.getTrcb() <= config.memSpec->tRC); + assert(config.getTfawb() <= config.memSpec->tNAW); */ } else { if (config.BankwiseLogic) { @@ -259,7 +259,7 @@ const std::vector &ControllerCore::getBanks() static std::vector banks; if (banks.size() == 0) { - for (unsigned int i = 0; i < config.memSpec.NumberOfBanks; i++) { + for (unsigned int i = 0; i < config.memSpec->NumberOfBanks; i++) { banks.push_back(Bank(i)); } } diff --git a/DRAMSys/library/src/controller/core/configuration/Configuration.cpp b/DRAMSys/library/src/controller/core/configuration/Configuration.cpp index 52904001..eb0918f3 100644 --- a/DRAMSys/library/src/controller/core/configuration/Configuration.cpp +++ b/DRAMSys/library/src/controller/core/configuration/Configuration.cpp @@ -349,10 +349,10 @@ void Configuration::setParameters(std::map std::uint64_t Configuration::getSimMemSizeInBytes() { // 1. Get number of banks, rows, columns and data width in bits for one die (or chip) - std::uint64_t banks = memSpec.NumberOfBanks; - std::uint64_t rows = memSpec.NumberOfRows; - std::uint64_t columns = memSpec.NumberOfColumns; - std::uint64_t bitWidth = memSpec.bitWidth; + std::uint64_t banks = memSpec->NumberOfBanks; + std::uint64_t rows = memSpec->NumberOfRows; + std::uint64_t columns = memSpec->NumberOfColumns; + std::uint64_t bitWidth = memSpec->bitWidth; // 2. Calculate size of one DRAM chip in bits std::uint64_t chipBitSize = banks * rows * columns * bitWidth; // 3. Calculate size of one DRAM chip in bytes @@ -381,7 +381,7 @@ std::uint64_t Configuration::getSimMemSizeInBytes() // The bus width is given in bits, e.g., 64-bit data bus, 128-bit data bus, etc. unsigned int Configuration::getDataBusWidth() { - unsigned int dataBusWidth = memSpec.bitWidth * NumberOfDevicesOnDIMM; + unsigned int dataBusWidth = memSpec->bitWidth * NumberOfDevicesOnDIMM; assert(dataBusWidth > 0); return dataBusWidth; } @@ -390,7 +390,7 @@ unsigned int Configuration::getDataBusWidth() unsigned int Configuration::getBytesPerBurst() { // First multiply to get the number of bits in a burst, then divide by 8 to get the value in bytes. The order is important. Think on a single x4 device. - unsigned int bytesPerBurst = (memSpec.BurstLength * getDataBusWidth()) / 8; + unsigned int bytesPerBurst = (memSpec->BurstLength * getDataBusWidth()) / 8; assert(bytesPerBurst > 0); if (NumberOfDevicesOnDIMM > 1) { @@ -399,7 +399,7 @@ unsigned int Configuration::getBytesPerBurst() // or burst element has N bytes. N = 2^(# bits for byte offset)). unsigned int burstElementSizeInBytes = AddressDecoder::getInstance().amount["bytes"]; - assert(bytesPerBurst == (burstElementSizeInBytes * memSpec.BurstLength)); + assert(bytesPerBurst == (burstElementSizeInBytes * memSpec->BurstLength)); } return bytesPerBurst; @@ -407,27 +407,27 @@ unsigned int Configuration::getBytesPerBurst() sc_time Configuration::getTrasb() { - return trasbclk * memSpec.clk; + return trasbclk * memSpec->clk; } sc_time Configuration::getTrrdb_L() { - return trrdblclk * memSpec.clk; + return trrdblclk * memSpec->clk; } sc_time Configuration::getTrrdb_S() { - return trrdbsclk * memSpec.clk; + return trrdbsclk * memSpec->clk; } sc_time Configuration::getTrpb() { - return trpbclk * memSpec.clk; + return trpbclk * memSpec->clk; } sc_time Configuration::getTrcb() { - return trcbclk * memSpec.clk; + return trcbclk * memSpec->clk; } sc_time Configuration::getTfawb() { - return tfawbclk * memSpec.clk; + return tfawbclk * memSpec->clk; } bool Configuration::getRGRBank(unsigned int w) { diff --git a/DRAMSys/library/src/controller/core/configuration/Configuration.h b/DRAMSys/library/src/controller/core/configuration/Configuration.h index bd1e4bfe..51d4079e 100644 --- a/DRAMSys/library/src/controller/core/configuration/Configuration.h +++ b/DRAMSys/library/src/controller/core/configuration/Configuration.h @@ -72,7 +72,7 @@ struct Configuration unsigned int Capsize = 5; sc_time getPowerDownTimeout() { - return powerDownTimeoutInClk * memSpec.clk; + return powerDownTimeoutInClk * memSpec->clk; } EPowerDownMode PowerDownMode = EPowerDownMode::Staggered; bool ReadWriteGrouping = false; @@ -139,7 +139,7 @@ struct Configuration unsigned long long int AddressOffset = 0; // MemSpec (from DRAM-Power XML) - MemSpec memSpec; + MemSpec *memSpec; void setParameter(std::string name, std::string value); void setParameters(std::map parameterMap); diff --git a/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.cpp b/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.cpp index 093479c8..79b9965f 100644 --- a/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.cpp +++ b/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.cpp @@ -139,34 +139,35 @@ void ConfigurationLoader::loadMemSpec(Configuration &config, string memspecUri) void ConfigurationLoader::loadMemSpec(Configuration &config, XMLElement *memspec) { - config.memSpec.MemoryId = queryStringParameter(memspec, "memoryId"); - config.memSpec.MemoryType = queryStringParameter(memspec, "memoryType"); + string memoryType = queryStringParameter(memspec, "memoryType"); - std::cout << "Before" << std::endl; - if (config.memSpec.MemoryType == "DDR4") { - delete(&Configuration::getInstance().memSpec); + if (memoryType == "DDR4") { Configuration::getInstance().memSpec = - *new MemSpecDDR4; + new MemSpecDDR4; loadDDR4(config, memspec); - } else if (config.memSpec.MemoryType == "DDR3") { - delete(&Configuration::getInstance().memSpec); + } else if (memoryType == "DDR3") { Configuration::getInstance().memSpec = - *new MemSpecDDR3; + new MemSpecDDR3; loadDDR3(config, memspec); - } else if (config.memSpec.MemoryType == "LPDDR4") { - delete(&Configuration::getInstance().memSpec); + } else if (memoryType == "LPDDR4") { Configuration::getInstance().memSpec = - *new MemSpecLPDDR4; + new MemSpecLPDDR4; loadLPDDR4(config, memspec); - } else if (config.memSpec.MemoryType == "WIDEIO_SDR") { - delete(&Configuration::getInstance().memSpec); + } else if (memoryType == "WIDEIO_SDR") { Configuration::getInstance().memSpec = - *new MemSpecWideIO; + new MemSpecWideIO; loadWideIO(config, memspec); } else { reportFatal("ConfigurationLoader", "Unsupported DRAM type"); } - std::cout << "After" << std::endl; + + loadCommons(config, memspec); +} + +void ConfigurationLoader::loadCommons(Configuration &config, XMLElement *memspec) +{ + config.memSpec->MemoryId = queryStringParameter(memspec, "memoryId"); + config.memSpec->MemoryType = queryStringParameter(memspec, "memoryType"); } void ConfigurationLoader::loadDDR3(Configuration &config, XMLElement *memspec) @@ -174,153 +175,152 @@ void ConfigurationLoader::loadDDR3(Configuration &config, XMLElement *memspec) //MemArchitecture XMLElement *architecture = memspec->FirstChildElement("memarchitecturespec"); - config.memSpec.NumberOfBanks = queryUIntParameter(architecture, "nbrOfBanks"); - config.memSpec.NumberOfBankGroups = 1; - config.memSpec.NumberOfRanks = queryUIntParameter(architecture, "nbrOfRanks"); - config.memSpec.BurstLength = queryUIntParameter(architecture, "burstLength"); - config.memSpec.nActivate = 4; - config.memSpec.DataRate = queryUIntParameter(architecture, "dataRate"); - config.memSpec.NumberOfRows = queryUIntParameter(architecture, "nbrOfRows"); - config.memSpec.NumberOfColumns = queryUIntParameter(architecture, + config.memSpec->NumberOfBanks = queryUIntParameter(architecture, "nbrOfBanks"); + config.memSpec->NumberOfBankGroups = 1; + config.memSpec->NumberOfRanks = queryUIntParameter(architecture, "nbrOfRanks"); + config.memSpec->BurstLength = queryUIntParameter(architecture, "burstLength"); + config.memSpec->nActivate = 4; + config.memSpec->DataRate = queryUIntParameter(architecture, "dataRate"); + config.memSpec->NumberOfRows = queryUIntParameter(architecture, "nbrOfRows"); + config.memSpec->NumberOfColumns = queryUIntParameter(architecture, "nbrOfColumns"); - config.memSpec.bitWidth = queryUIntParameter(architecture, "width"); - config.memSpec.DLL = true; - config.memSpec.termination = true; + config.memSpec->bitWidth = queryUIntParameter(architecture, "width"); + config.memSpec->DLL = true; + config.memSpec->termination = true; //MemTimings XMLElement *timings = memspec->FirstChildElement("memtimingspec"); - config.memSpec.clkMHz = queryDoubleParameter(timings, "clkMhz"); - config.memSpec.clk = FrequencyToClk(config.memSpec.clkMHz); - sc_time clk = config.memSpec.clk; - config.memSpec.tRP = clk * queryUIntParameter(timings, "RP"); - config.memSpec.tRAS = clk * queryUIntParameter(timings, "RAS"); - config.memSpec.tRC = clk * queryUIntParameter(timings, "RC"); - config.memSpec.tRTP = clk * queryUIntParameter(timings, "RTP"); - config.memSpec.tRRD_S = clk * queryUIntParameter(timings, "RRD"); - config.memSpec.tRRD_L = clk * queryUIntParameter(timings, "RRD"); - config.memSpec.tCCD_S = clk * queryUIntParameter(timings, "CCD"); - config.memSpec.tCCD_L = clk * queryUIntParameter(timings, "CCD"); - config.memSpec.tRCD = clk * queryUIntParameter(timings, "RCD"); - config.memSpec.tNAW = clk * queryUIntParameter(timings, "FAW"); - config.memSpec.tRL = clk * queryUIntParameter(timings, "RL"); - config.memSpec.tWL = clk * queryUIntParameter(timings, "WL"); - config.memSpec.tWR = clk * queryUIntParameter(timings, "WR"); - config.memSpec.tWTR_S = clk * queryUIntParameter(timings, "WTR"); - config.memSpec.tWTR_L = clk * queryUIntParameter(timings, "WTR"); - config.memSpec.tCKESR = clk * queryUIntParameter(timings, "CKESR"); - config.memSpec.tCKE = clk * queryUIntParameter(timings, "CKE"); - config.memSpec.tXP = clk * queryUIntParameter(timings, "XP"); - config.memSpec.tXPDLL = clk * queryUIntParameter(timings, "XPDLL"); - config.memSpec.tXSR = clk * queryUIntParameter(timings, "XS"); - config.memSpec.tXSRDLL = clk * queryUIntParameter(timings, "XSDLL"); - config.memSpec.tAL = clk * queryUIntParameter(timings, "AL"); - config.memSpec.tRFC = clk * queryUIntParameter(timings, "RFC"); - config.memSpec.tREFI = clk * queryUIntParameter(timings, "REFI"); - config.memSpec.tDQSCK = clk * queryUIntParameter(timings, "DQSCK"); + config.memSpec->clkMHz = queryDoubleParameter(timings, "clkMhz"); + config.memSpec->clk = FrequencyToClk(config.memSpec->clkMHz); + sc_time clk = config.memSpec->clk; + config.memSpec->tRP = clk * queryUIntParameter(timings, "RP"); + config.memSpec->tRAS = clk * queryUIntParameter(timings, "RAS"); + config.memSpec->tRC = clk * queryUIntParameter(timings, "RC"); + config.memSpec->tRTP = clk * queryUIntParameter(timings, "RTP"); + config.memSpec->tRRD_S = clk * queryUIntParameter(timings, "RRD"); + config.memSpec->tRRD_L = clk * queryUIntParameter(timings, "RRD"); + config.memSpec->tCCD_S = clk * queryUIntParameter(timings, "CCD"); + config.memSpec->tCCD_L = clk * queryUIntParameter(timings, "CCD"); + config.memSpec->tRCD = clk * queryUIntParameter(timings, "RCD"); + config.memSpec->tNAW = clk * queryUIntParameter(timings, "FAW"); + config.memSpec->tRL = clk * queryUIntParameter(timings, "RL"); + config.memSpec->tWL = clk * queryUIntParameter(timings, "WL"); + config.memSpec->tWR = clk * queryUIntParameter(timings, "WR"); + config.memSpec->tWTR_S = clk * queryUIntParameter(timings, "WTR"); + config.memSpec->tWTR_L = clk * queryUIntParameter(timings, "WTR"); + config.memSpec->tCKESR = clk * queryUIntParameter(timings, "CKESR"); + config.memSpec->tCKE = clk * queryUIntParameter(timings, "CKE"); + config.memSpec->tXP = clk * queryUIntParameter(timings, "XP"); + config.memSpec->tXPDLL = clk * queryUIntParameter(timings, "XPDLL"); + config.memSpec->tXSR = clk * queryUIntParameter(timings, "XS"); + config.memSpec->tXSRDLL = clk * queryUIntParameter(timings, "XSDLL"); + config.memSpec->tAL = clk * queryUIntParameter(timings, "AL"); + config.memSpec->tRFC = clk * queryUIntParameter(timings, "RFC"); + config.memSpec->tREFI = clk * queryUIntParameter(timings, "REFI"); + config.memSpec->tDQSCK = clk * queryUIntParameter(timings, "DQSCK"); - config.memSpec.refreshTimings.clear(); - for (unsigned int i = 0; i < config.memSpec.NumberOfBanks; ++i) { - config.memSpec.refreshTimings[Bank(i)] = RefreshTiming(config.memSpec.tRFC, - config.memSpec.tREFI); + config.memSpec->refreshTimings.clear(); + for (unsigned int i = 0; i < config.memSpec->NumberOfBanks; ++i) { + config.memSpec->refreshTimings[Bank(i)] = RefreshTiming(config.memSpec->tRFC, + config.memSpec->tREFI); } // Currents and Volatages: TODO Check if this is correct. XMLElement *powers = memspec->FirstChildElement("mempowerspec"); - config.memSpec.iDD0 = queryDoubleParameter(powers, "idd0"); - config.memSpec.iDD02 = 0; - config.memSpec.iDD2P0 = queryDoubleParameter(powers, "idd2p0"); - config.memSpec.iDD2P1 = queryDoubleParameter(powers, "idd2p1"); - config.memSpec.iDD2N = queryDoubleParameter(powers, "idd2n"); - config.memSpec.iDD3P0 = queryDoubleParameter(powers, "idd3p0"); - config.memSpec.iDD3P1 = queryDoubleParameter(powers, "idd3p1"); - config.memSpec.iDD3N = queryDoubleParameter(powers, "idd3n"); - config.memSpec.iDD4R = queryDoubleParameter(powers, "idd4r"); - config.memSpec.iDD4W = queryDoubleParameter(powers, "idd4w"); - config.memSpec.iDD5 = queryDoubleParameter(powers, "idd5"); - config.memSpec.iDD6 = queryDoubleParameter(powers, "idd6"); - config.memSpec.iDD62 = 0; - config.memSpec.vDD = queryDoubleParameter(powers, "vdd"); - config.memSpec.vDD2 = 0; + config.memSpec->iDD0 = queryDoubleParameter(powers, "idd0"); + config.memSpec->iDD02 = 0; + config.memSpec->iDD2P0 = queryDoubleParameter(powers, "idd2p0"); + config.memSpec->iDD2P1 = queryDoubleParameter(powers, "idd2p1"); + config.memSpec->iDD2N = queryDoubleParameter(powers, "idd2n"); + config.memSpec->iDD3P0 = queryDoubleParameter(powers, "idd3p0"); + config.memSpec->iDD3P1 = queryDoubleParameter(powers, "idd3p1"); + config.memSpec->iDD3N = queryDoubleParameter(powers, "idd3n"); + config.memSpec->iDD4R = queryDoubleParameter(powers, "idd4r"); + config.memSpec->iDD4W = queryDoubleParameter(powers, "idd4w"); + config.memSpec->iDD5 = queryDoubleParameter(powers, "idd5"); + config.memSpec->iDD6 = queryDoubleParameter(powers, "idd6"); + config.memSpec->iDD62 = 0; + config.memSpec->vDD = queryDoubleParameter(powers, "vdd"); + config.memSpec->vDD2 = 0; } - void ConfigurationLoader::loadDDR4(Configuration &config, XMLElement *memspec) { //MemArchitecture XMLElement *architecture = memspec->FirstChildElement("memarchitecturespec"); - config.memSpec.NumberOfBanks = queryUIntParameter(architecture, "nbrOfBanks"); - config.memSpec.NumberOfBankGroups = queryUIntParameter(architecture, + config.memSpec->NumberOfBanks = queryUIntParameter(architecture, "nbrOfBanks"); + config.memSpec->NumberOfBankGroups = queryUIntParameter(architecture, "nbrOfBankGroups"); - config.memSpec.NumberOfRanks = queryUIntParameter(architecture, "nbrOfRanks"); - config.memSpec.BurstLength = queryUIntParameter(architecture, "burstLength"); - config.memSpec.nActivate = 4; - config.memSpec.DataRate = queryUIntParameter(architecture, "dataRate"); - config.memSpec.NumberOfRows = queryUIntParameter(architecture, "nbrOfRows"); - config.memSpec.NumberOfColumns = queryUIntParameter(architecture, + config.memSpec->NumberOfRanks = queryUIntParameter(architecture, "nbrOfRanks"); + config.memSpec->BurstLength = queryUIntParameter(architecture, "burstLength"); + config.memSpec->nActivate = 4; + config.memSpec->DataRate = queryUIntParameter(architecture, "dataRate"); + config.memSpec->NumberOfRows = queryUIntParameter(architecture, "nbrOfRows"); + config.memSpec->NumberOfColumns = queryUIntParameter(architecture, "nbrOfColumns"); - config.memSpec.bitWidth = queryUIntParameter(architecture, "width"); - config.memSpec.DLL = true; - config.memSpec.termination = true; + config.memSpec->bitWidth = queryUIntParameter(architecture, "width"); + config.memSpec->DLL = true; + config.memSpec->termination = true; //MemTimings XMLElement *timings = memspec->FirstChildElement("memtimingspec"); - config.memSpec.clkMHz = queryDoubleParameter(timings, "clkMhz"); - config.memSpec.clk = FrequencyToClk(config.memSpec.clkMHz); - sc_time clk = config.memSpec.clk; - config.memSpec.tRP = clk * queryUIntParameter(timings, "RP"); - config.memSpec.tRAS = clk * queryUIntParameter(timings, "RAS"); - config.memSpec.tRC = clk * queryUIntParameter(timings, "RC"); - config.memSpec.tRTP = clk * queryUIntParameter(timings, "RTP"); - config.memSpec.tRRD_S = clk * queryUIntParameter(timings, "RRD_S"); - config.memSpec.tRRD_L = clk * queryUIntParameter(timings, "RRD_L"); - config.memSpec.tCCD_S = clk * queryUIntParameter(timings, "CCD_S"); - config.memSpec.tCCD_L = clk * queryUIntParameter(timings, "CCD_L"); - config.memSpec.tRCD = clk * queryUIntParameter(timings, "RCD"); - config.memSpec.tNAW = clk * queryUIntParameter(timings, "FAW"); - config.memSpec.tRL = clk * queryUIntParameter(timings, "RL"); - config.memSpec.tWL = clk * queryUIntParameter(timings, "WL"); - config.memSpec.tWR = clk * queryUIntParameter(timings, "WR"); - config.memSpec.tWTR_S = clk * queryUIntParameter(timings, "WTR_S"); - config.memSpec.tWTR_L = clk * queryUIntParameter(timings, "WTR_L"); - config.memSpec.tCKESR = clk * queryUIntParameter(timings, "CKESR"); - config.memSpec.tCKE = clk * queryUIntParameter(timings, "CKE"); - config.memSpec.tXP = clk * queryUIntParameter(timings, "XP"); - config.memSpec.tXPDLL = clk * queryUIntParameter(timings, "XPDLL"); - config.memSpec.tXSR = clk * queryUIntParameter(timings, "XS"); - config.memSpec.tXSRDLL = clk * queryUIntParameter(timings, "XSDLL"); - config.memSpec.tAL = clk * queryUIntParameter(timings, "AL"); - config.memSpec.tRFC = clk * queryUIntParameter(timings, "RFC"); - config.memSpec.tRFC2 = clk * queryUIntParameter(timings, "RFC2"); - config.memSpec.tRFC4 = clk * queryUIntParameter(timings, "RFC4"); - config.memSpec.tREFI = clk * queryUIntParameter(timings, "REFI"); - config.memSpec.tDQSCK = clk * queryUIntParameter(timings, "DQSCK"); + config.memSpec->clkMHz = queryDoubleParameter(timings, "clkMhz"); + config.memSpec->clk = FrequencyToClk(config.memSpec->clkMHz); + sc_time clk = config.memSpec->clk; + config.memSpec->tRP = clk * queryUIntParameter(timings, "RP"); + config.memSpec->tRAS = clk * queryUIntParameter(timings, "RAS"); + config.memSpec->tRC = clk * queryUIntParameter(timings, "RC"); + config.memSpec->tRTP = clk * queryUIntParameter(timings, "RTP"); + config.memSpec->tRRD_S = clk * queryUIntParameter(timings, "RRD_S"); + config.memSpec->tRRD_L = clk * queryUIntParameter(timings, "RRD_L"); + config.memSpec->tCCD_S = clk * queryUIntParameter(timings, "CCD_S"); + config.memSpec->tCCD_L = clk * queryUIntParameter(timings, "CCD_L"); + config.memSpec->tRCD = clk * queryUIntParameter(timings, "RCD"); + config.memSpec->tNAW = clk * queryUIntParameter(timings, "FAW"); + config.memSpec->tRL = clk * queryUIntParameter(timings, "RL"); + config.memSpec->tWL = clk * queryUIntParameter(timings, "WL"); + config.memSpec->tWR = clk * queryUIntParameter(timings, "WR"); + config.memSpec->tWTR_S = clk * queryUIntParameter(timings, "WTR_S"); + config.memSpec->tWTR_L = clk * queryUIntParameter(timings, "WTR_L"); + config.memSpec->tCKESR = clk * queryUIntParameter(timings, "CKESR"); + config.memSpec->tCKE = clk * queryUIntParameter(timings, "CKE"); + config.memSpec->tXP = clk * queryUIntParameter(timings, "XP"); + config.memSpec->tXPDLL = clk * queryUIntParameter(timings, "XPDLL"); + config.memSpec->tXSR = clk * queryUIntParameter(timings, "XS"); + config.memSpec->tXSRDLL = clk * queryUIntParameter(timings, "XSDLL"); + config.memSpec->tAL = clk * queryUIntParameter(timings, "AL"); + config.memSpec->tRFC = clk * queryUIntParameter(timings, "RFC"); + config.memSpec->tRFC2 = clk * queryUIntParameter(timings, "RFC2"); + config.memSpec->tRFC4 = clk * queryUIntParameter(timings, "RFC4"); + config.memSpec->tREFI = clk * queryUIntParameter(timings, "REFI"); + config.memSpec->tDQSCK = clk * queryUIntParameter(timings, "DQSCK"); - config.memSpec.refreshTimings.clear(); - for (unsigned int i = 0; i < config.memSpec.NumberOfBanks; ++i) { - config.memSpec.refreshTimings[Bank(i)] = RefreshTiming(config.memSpec.tRFC, - config.memSpec.tRFC2, - config.memSpec.tRFC4, - config.memSpec.tREFI); + config.memSpec->refreshTimings.clear(); + for (unsigned int i = 0; i < config.memSpec->NumberOfBanks; ++i) { + config.memSpec->refreshTimings[Bank(i)] = RefreshTiming(config.memSpec->tRFC, + config.memSpec->tRFC2, + config.memSpec->tRFC4, + config.memSpec->tREFI); } // Currents and Volatages: XMLElement *powers = memspec->FirstChildElement("mempowerspec"); - config.memSpec.iDD0 = queryDoubleParameter(powers, "idd0"); - config.memSpec.iDD02 = queryDoubleParameter(powers, "idd02"); - config.memSpec.iDD2P0 = queryDoubleParameter(powers, "idd2p0"); - config.memSpec.iDD2P1 = queryDoubleParameter(powers, "idd2p1"); - config.memSpec.iDD2N = queryDoubleParameter(powers, "idd2n"); - config.memSpec.iDD3P0 = queryDoubleParameter(powers, "idd3p0"); - config.memSpec.iDD3P1 = queryDoubleParameter(powers, "idd3p1"); - config.memSpec.iDD3N = queryDoubleParameter(powers, "idd3n"); - config.memSpec.iDD4R = queryDoubleParameter(powers, "idd4r"); - config.memSpec.iDD4W = queryDoubleParameter(powers, "idd4w"); - config.memSpec.iDD5 = queryDoubleParameter(powers, "idd5"); - config.memSpec.iDD6 = queryDoubleParameter(powers, "idd6"); - config.memSpec.iDD62 = queryDoubleParameter(powers, "idd62"); - config.memSpec.vDD = queryDoubleParameter(powers, "vdd"); - config.memSpec.vDD2 = queryDoubleParameter(powers, "vdd2"); + config.memSpec->iDD0 = queryDoubleParameter(powers, "idd0"); + config.memSpec->iDD02 = queryDoubleParameter(powers, "idd02"); + config.memSpec->iDD2P0 = queryDoubleParameter(powers, "idd2p0"); + config.memSpec->iDD2P1 = queryDoubleParameter(powers, "idd2p1"); + config.memSpec->iDD2N = queryDoubleParameter(powers, "idd2n"); + config.memSpec->iDD3P0 = queryDoubleParameter(powers, "idd3p0"); + config.memSpec->iDD3P1 = queryDoubleParameter(powers, "idd3p1"); + config.memSpec->iDD3N = queryDoubleParameter(powers, "idd3n"); + config.memSpec->iDD4R = queryDoubleParameter(powers, "idd4r"); + config.memSpec->iDD4W = queryDoubleParameter(powers, "idd4w"); + config.memSpec->iDD5 = queryDoubleParameter(powers, "idd5"); + config.memSpec->iDD6 = queryDoubleParameter(powers, "idd6"); + config.memSpec->iDD62 = queryDoubleParameter(powers, "idd62"); + config.memSpec->vDD = queryDoubleParameter(powers, "vdd"); + config.memSpec->vDD2 = queryDoubleParameter(powers, "vdd2"); } // TODO: fix this for LPDDR4 @@ -329,76 +329,76 @@ void ConfigurationLoader::loadLPDDR4(Configuration &config, XMLElement *memspec) //MemArchitecture: XMLElement *architecture = memspec->FirstChildElement("memarchitecturespec"); - config.memSpec.NumberOfBanks = queryUIntParameter(architecture, "nbrOfBanks"); - config.memSpec.NumberOfBankGroups = 1; - config.memSpec.NumberOfRanks = queryUIntParameter(architecture, "nbrOfRanks"); - config.memSpec.BurstLength = queryUIntParameter(architecture, "burstLength"); - config.memSpec.nActivate = 4; - config.memSpec.DataRate = queryUIntParameter(architecture, "dataRate"); - config.memSpec.NumberOfRows = queryUIntParameter(architecture, "nbrOfRows"); - config.memSpec.NumberOfColumns = queryUIntParameter(architecture, + config.memSpec->NumberOfBanks = queryUIntParameter(architecture, "nbrOfBanks"); + config.memSpec->NumberOfBankGroups = 1; + config.memSpec->NumberOfRanks = queryUIntParameter(architecture, "nbrOfRanks"); + config.memSpec->BurstLength = queryUIntParameter(architecture, "burstLength"); + config.memSpec->nActivate = 4; + config.memSpec->DataRate = queryUIntParameter(architecture, "dataRate"); + config.memSpec->NumberOfRows = queryUIntParameter(architecture, "nbrOfRows"); + config.memSpec->NumberOfColumns = queryUIntParameter(architecture, "nbrOfColumns"); - config.memSpec.bitWidth = queryUIntParameter(architecture, "width"); - config.memSpec.DLL = false; // TODO: Correct? - config.memSpec.termination = true; // TODO: Correct? + config.memSpec->bitWidth = queryUIntParameter(architecture, "width"); + config.memSpec->DLL = false; // TODO: Correct? + config.memSpec->termination = true; // TODO: Correct? //MemTimings XMLElement *timings = memspec->FirstChildElement("memtimingspec"); - config.memSpec.clkMHz = queryDoubleParameter(timings, "clkMhz"); - config.memSpec.clk = FrequencyToClk(config.memSpec.clkMHz); - sc_time clk = config.memSpec.clk; - config.memSpec.tRP = clk * queryUIntParameter(timings, "RPPB"); - config.memSpec.tRPAB = clk * queryUIntParameter(timings, "RPAB"); - config.memSpec.tRAS = clk * queryUIntParameter(timings, "RAS"); - config.memSpec.tRC = clk * queryUIntParameter(timings, "RC"); - config.memSpec.tRTP = clk * queryUIntParameter(timings, "RTP"); - config.memSpec.tRRD_S = clk * queryUIntParameter(timings, "RRD"); - config.memSpec.tRRD_L = clk * queryUIntParameter(timings, "RRD"); - config.memSpec.tCCD_S = clk * queryUIntParameter(timings, "CCD"); - config.memSpec.tCCD_L = clk * queryUIntParameter(timings, "CCD"); - config.memSpec.tRCD = clk * queryUIntParameter(timings, "RCD"); - config.memSpec.tNAW = clk * queryUIntParameter(timings, "FAW"); - config.memSpec.tRL = clk * queryUIntParameter(timings, "RL"); - config.memSpec.tWL = clk * queryUIntParameter(timings, "WL"); - config.memSpec.tWR = clk * queryUIntParameter(timings, "WR"); - config.memSpec.tWTR_S = clk * queryUIntParameter(timings, "WTR"); - config.memSpec.tWTR_L = clk * queryUIntParameter(timings, "WTR"); - config.memSpec.tCKESR = clk * queryUIntParameter(timings, "CKESR"); - config.memSpec.tCKE = clk * queryUIntParameter(timings, "CKE"); - config.memSpec.tXP = clk * queryUIntParameter(timings, "XP"); - config.memSpec.tXPDLL = clk * queryUIntParameter(timings, "XP"); - config.memSpec.tXSR = clk * queryUIntParameter(timings, "XS"); - config.memSpec.tXSRDLL = clk * queryUIntParameter(timings, "XS"); - config.memSpec.tAL = clk * queryUIntParameter(timings, "AL"); - config.memSpec.tRFC = clk * queryUIntParameter(timings, "RFCAB"); - // TODO: config.memSpec.tRFCPB = clk * queryUIntParameter(timings, "RFCPB"); - config.memSpec.tREFI = clk * queryUIntParameter(timings, "REFIAB"); - // TODO: config.memSpec.tREFIPB = clk * queryUIntParameter(timings, "RFCPB"); - config.memSpec.tDQSCK = clk * queryUIntParameter(timings, "DQSCK"); + config.memSpec->clkMHz = queryDoubleParameter(timings, "clkMhz"); + config.memSpec->clk = FrequencyToClk(config.memSpec->clkMHz); + sc_time clk = config.memSpec->clk; + config.memSpec->tRP = clk * queryUIntParameter(timings, "RPPB"); + config.memSpec->tRPAB = clk * queryUIntParameter(timings, "RPAB"); + config.memSpec->tRAS = clk * queryUIntParameter(timings, "RAS"); + config.memSpec->tRC = clk * queryUIntParameter(timings, "RC"); + config.memSpec->tRTP = clk * queryUIntParameter(timings, "RTP"); + config.memSpec->tRRD_S = clk * queryUIntParameter(timings, "RRD"); + config.memSpec->tRRD_L = clk * queryUIntParameter(timings, "RRD"); + config.memSpec->tCCD_S = clk * queryUIntParameter(timings, "CCD"); + config.memSpec->tCCD_L = clk * queryUIntParameter(timings, "CCD"); + config.memSpec->tRCD = clk * queryUIntParameter(timings, "RCD"); + config.memSpec->tNAW = clk * queryUIntParameter(timings, "FAW"); + config.memSpec->tRL = clk * queryUIntParameter(timings, "RL"); + config.memSpec->tWL = clk * queryUIntParameter(timings, "WL"); + config.memSpec->tWR = clk * queryUIntParameter(timings, "WR"); + config.memSpec->tWTR_S = clk * queryUIntParameter(timings, "WTR"); + config.memSpec->tWTR_L = clk * queryUIntParameter(timings, "WTR"); + config.memSpec->tCKESR = clk * queryUIntParameter(timings, "CKESR"); + config.memSpec->tCKE = clk * queryUIntParameter(timings, "CKE"); + config.memSpec->tXP = clk * queryUIntParameter(timings, "XP"); + config.memSpec->tXPDLL = clk * queryUIntParameter(timings, "XP"); + config.memSpec->tXSR = clk * queryUIntParameter(timings, "XS"); + config.memSpec->tXSRDLL = clk * queryUIntParameter(timings, "XS"); + config.memSpec->tAL = clk * queryUIntParameter(timings, "AL"); + config.memSpec->tRFC = clk * queryUIntParameter(timings, "RFCAB"); + // TODO: config.memSpec->tRFCPB = clk * queryUIntParameter(timings, "RFCPB"); + config.memSpec->tREFI = clk * queryUIntParameter(timings, "REFIAB"); + // TODO: config.memSpec->tREFIPB = clk * queryUIntParameter(timings, "RFCPB"); + config.memSpec->tDQSCK = clk * queryUIntParameter(timings, "DQSCK"); - config.memSpec.refreshTimings.clear(); - for (unsigned int i = 0; i < config.memSpec.NumberOfBanks; ++i) { - config.memSpec.refreshTimings[Bank(i)] = RefreshTiming(config.memSpec.tRFC, - config.memSpec.tREFI); + config.memSpec->refreshTimings.clear(); + for (unsigned int i = 0; i < config.memSpec->NumberOfBanks; ++i) { + config.memSpec->refreshTimings[Bank(i)] = RefreshTiming(config.memSpec->tRFC, + config.memSpec->tREFI); } // Currents and Volatages: XMLElement *powers = memspec->FirstChildElement("mempowerspec"); - config.memSpec.iDD0 = queryDoubleParameter(powers, "idd0"); - config.memSpec.iDD02 = queryDoubleParameter(powers, "idd02"); - config.memSpec.iDD2P0 = queryDoubleParameter(powers, "idd2p"); - config.memSpec.iDD2P1 = queryDoubleParameter(powers, "idd2p2"); - config.memSpec.iDD2N = queryDoubleParameter(powers, "idd2n"); - config.memSpec.iDD3P0 = queryDoubleParameter(powers, "idd3p"); - config.memSpec.iDD3P1 = queryDoubleParameter(powers, "idd3p2"); - config.memSpec.iDD3N = queryDoubleParameter(powers, "idd3n"); - config.memSpec.iDD4R = queryDoubleParameter(powers, "idd4r"); - config.memSpec.iDD4W = queryDoubleParameter(powers, "idd4w"); - config.memSpec.iDD5 = queryDoubleParameter(powers, "idd5"); - config.memSpec.iDD6 = queryDoubleParameter(powers, "idd6"); - config.memSpec.iDD62 = queryDoubleParameter(powers, "idd62"); - config.memSpec.vDD = queryDoubleParameter(powers, "vdd"); - config.memSpec.vDD2 = queryDoubleParameter(powers, "vdd2"); + config.memSpec->iDD0 = queryDoubleParameter(powers, "idd0"); + config.memSpec->iDD02 = queryDoubleParameter(powers, "idd02"); + config.memSpec->iDD2P0 = queryDoubleParameter(powers, "idd2p"); + config.memSpec->iDD2P1 = queryDoubleParameter(powers, "idd2p2"); + config.memSpec->iDD2N = queryDoubleParameter(powers, "idd2n"); + config.memSpec->iDD3P0 = queryDoubleParameter(powers, "idd3p"); + config.memSpec->iDD3P1 = queryDoubleParameter(powers, "idd3p2"); + config.memSpec->iDD3N = queryDoubleParameter(powers, "idd3n"); + config.memSpec->iDD4R = queryDoubleParameter(powers, "idd4r"); + config.memSpec->iDD4W = queryDoubleParameter(powers, "idd4w"); + config.memSpec->iDD5 = queryDoubleParameter(powers, "idd5"); + config.memSpec->iDD6 = queryDoubleParameter(powers, "idd6"); + config.memSpec->iDD62 = queryDoubleParameter(powers, "idd62"); + config.memSpec->vDD = queryDoubleParameter(powers, "vdd"); + config.memSpec->vDD2 = queryDoubleParameter(powers, "vdd2"); } void ConfigurationLoader::loadWideIO(Configuration &config, XMLElement *memspec) @@ -406,79 +406,79 @@ void ConfigurationLoader::loadWideIO(Configuration &config, XMLElement *memspec) //MemSpecification XMLElement *architecture = memspec->FirstChildElement("memarchitecturespec"); - config.memSpec.NumberOfBanks = queryUIntParameter(architecture, "nbrOfBanks"); - config.memSpec.NumberOfBankGroups = 1; - config.memSpec.NumberOfRanks = 1; - config.memSpec.BurstLength = queryUIntParameter(architecture, "burstLength"); - config.memSpec.nActivate = 2; - config.memSpec.DataRate = queryUIntParameter(architecture, "dataRate"); - config.memSpec.NumberOfRows = queryUIntParameter(architecture, "nbrOfRows"); - config.memSpec.NumberOfColumns = queryUIntParameter(architecture, + config.memSpec->NumberOfBanks = queryUIntParameter(architecture, "nbrOfBanks"); + config.memSpec->NumberOfBankGroups = 1; + config.memSpec->NumberOfRanks = 1; + config.memSpec->BurstLength = queryUIntParameter(architecture, "burstLength"); + config.memSpec->nActivate = 2; + config.memSpec->DataRate = queryUIntParameter(architecture, "dataRate"); + config.memSpec->NumberOfRows = queryUIntParameter(architecture, "nbrOfRows"); + config.memSpec->NumberOfColumns = queryUIntParameter(architecture, "nbrOfColumns"); - config.memSpec.bitWidth = queryUIntParameter(architecture, "width"); - config.memSpec.DLL = false; - config.memSpec.termination = false; + config.memSpec->bitWidth = queryUIntParameter(architecture, "width"); + config.memSpec->DLL = false; + config.memSpec->termination = false; //MemTimings XMLElement *timings = memspec->FirstChildElement("memtimingspec"); - config.memSpec.clkMHz = queryDoubleParameter(timings, "clkMhz"); - config.memSpec.clk = FrequencyToClk(config.memSpec.clkMHz); - sc_time clk = config.memSpec.clk; - config.memSpec.tRP = clk * queryUIntParameter(timings, "RP"); - config.memSpec.tRAS = clk * queryUIntParameter(timings, "RAS"); - config.memSpec.tRC = clk * queryUIntParameter(timings, "RC"); - config.memSpec.tRRD_S = clk * queryUIntParameter(timings, "RRD"); - config.memSpec.tRRD_L = config.memSpec.tRRD_S; - config.memSpec.tCCD_S = clk * queryUIntParameter(timings, "CCD"); - config.memSpec.tCCD_L = config.memSpec.tCCD_S; - config.memSpec.tRCD = clk * queryUIntParameter(timings, "RCD"); - config.memSpec.tNAW = clk * queryUIntParameter(timings, "TAW"); - config.memSpec.tRL = clk * queryUIntParameter(timings, "RL"); - config.memSpec.tWL = clk * queryUIntParameter(timings, "WL"); - config.memSpec.tWR = clk * queryUIntParameter(timings, "WR"); - config.memSpec.tWTR_S = clk * queryUIntParameter(timings, "WTR"); - config.memSpec.tWTR_L = config.memSpec.tWTR_S; - config.memSpec.tRTP = clk * queryUIntParameter(timings, "RTP"); - config.memSpec.tCKESR = clk * queryUIntParameter(timings, "CKESR"); - config.memSpec.tCKE = clk * queryUIntParameter(timings, "CKE"); - config.memSpec.tXP = clk * queryUIntParameter(timings, "XP"); - config.memSpec.tXPDLL = config.memSpec.tXP; - config.memSpec.tXSR = clk * queryUIntParameter(timings, "XS"); - config.memSpec.tXSRDLL = config.memSpec.tXSR; - config.memSpec.tAL = clk * queryUIntParameter(timings, "AL"); - config.memSpec.tRFC = clk * queryUIntParameter(timings, "RFC"); - config.memSpec.tREFI = clk * queryUIntParameter(timings, "REFI"); + config.memSpec->clkMHz = queryDoubleParameter(timings, "clkMhz"); + config.memSpec->clk = FrequencyToClk(config.memSpec->clkMHz); + sc_time clk = config.memSpec->clk; + config.memSpec->tRP = clk * queryUIntParameter(timings, "RP"); + config.memSpec->tRAS = clk * queryUIntParameter(timings, "RAS"); + config.memSpec->tRC = clk * queryUIntParameter(timings, "RC"); + config.memSpec->tRRD_S = clk * queryUIntParameter(timings, "RRD"); + config.memSpec->tRRD_L = config.memSpec->tRRD_S; + config.memSpec->tCCD_S = clk * queryUIntParameter(timings, "CCD"); + config.memSpec->tCCD_L = config.memSpec->tCCD_S; + config.memSpec->tRCD = clk * queryUIntParameter(timings, "RCD"); + config.memSpec->tNAW = clk * queryUIntParameter(timings, "TAW"); + config.memSpec->tRL = clk * queryUIntParameter(timings, "RL"); + config.memSpec->tWL = clk * queryUIntParameter(timings, "WL"); + config.memSpec->tWR = clk * queryUIntParameter(timings, "WR"); + config.memSpec->tWTR_S = clk * queryUIntParameter(timings, "WTR"); + config.memSpec->tWTR_L = config.memSpec->tWTR_S; + config.memSpec->tRTP = clk * queryUIntParameter(timings, "RTP"); + config.memSpec->tCKESR = clk * queryUIntParameter(timings, "CKESR"); + config.memSpec->tCKE = clk * queryUIntParameter(timings, "CKE"); + config.memSpec->tXP = clk * queryUIntParameter(timings, "XP"); + config.memSpec->tXPDLL = config.memSpec->tXP; + config.memSpec->tXSR = clk * queryUIntParameter(timings, "XS"); + config.memSpec->tXSRDLL = config.memSpec->tXSR; + config.memSpec->tAL = clk * queryUIntParameter(timings, "AL"); + config.memSpec->tRFC = clk * queryUIntParameter(timings, "RFC"); + config.memSpec->tREFI = clk * queryUIntParameter(timings, "REFI"); - config.memSpec.refreshTimings.clear(); - for (unsigned int i = 0; i < config.memSpec.NumberOfBanks; ++i) { - config.memSpec.refreshTimings[Bank(i)] = RefreshTiming(config.memSpec.tRFC, - config.memSpec.tREFI); + config.memSpec->refreshTimings.clear(); + for (unsigned int i = 0; i < config.memSpec->NumberOfBanks; ++i) { + config.memSpec->refreshTimings[Bank(i)] = RefreshTiming(config.memSpec->tRFC, + config.memSpec->tREFI); } // Currents and Volatages: XMLElement *powers = memspec->FirstChildElement("mempowerspec"); - config.memSpec.iDD0 = queryDoubleParameter(powers, "idd0"); - config.memSpec.iDD02 = queryDoubleParameter(powers, "idd02"); - config.memSpec.iDD2P0 = queryDoubleParameter(powers, "idd2p0"); - config.memSpec.iDD2P02 = queryDoubleParameter(powers, "idd2p02"); - config.memSpec.iDD2P1 = queryDoubleParameter(powers, "idd2p1"); - config.memSpec.iDD2P12 = queryDoubleParameter(powers, "idd2p12"); - config.memSpec.iDD2N = queryDoubleParameter(powers, "idd2n"); - config.memSpec.iDD2N2 = queryDoubleParameter(powers, "idd2n2"); - config.memSpec.iDD3P0 = queryDoubleParameter(powers, "idd3p0"); - config.memSpec.iDD3P02 = queryDoubleParameter(powers, "idd3p02"); - config.memSpec.iDD3P1 = queryDoubleParameter(powers, "idd3p1"); - config.memSpec.iDD3P12 = queryDoubleParameter(powers, "idd3p12"); - config.memSpec.iDD3N = queryDoubleParameter(powers, "idd3n"); - config.memSpec.iDD3N2 = queryDoubleParameter(powers, "idd3n2"); - config.memSpec.iDD4R = queryDoubleParameter(powers, "idd4r"); - config.memSpec.iDD4R2 = queryDoubleParameter(powers, "idd4r2"); - config.memSpec.iDD4W = queryDoubleParameter(powers, "idd4w"); - config.memSpec.iDD4W2 = queryDoubleParameter(powers, "idd4w2"); - config.memSpec.iDD5 = queryDoubleParameter(powers, "idd5"); - config.memSpec.iDD52 = queryDoubleParameter(powers, "idd52"); - config.memSpec.iDD6 = queryDoubleParameter(powers, "idd6"); - config.memSpec.iDD62 = queryDoubleParameter(powers, "idd62"); - config.memSpec.vDD = queryDoubleParameter(powers, "vdd"); - config.memSpec.vDD2 = queryDoubleParameter(powers, "vdd2"); + config.memSpec->iDD0 = queryDoubleParameter(powers, "idd0"); + config.memSpec->iDD02 = queryDoubleParameter(powers, "idd02"); + config.memSpec->iDD2P0 = queryDoubleParameter(powers, "idd2p0"); + config.memSpec->iDD2P02 = queryDoubleParameter(powers, "idd2p02"); + config.memSpec->iDD2P1 = queryDoubleParameter(powers, "idd2p1"); + config.memSpec->iDD2P12 = queryDoubleParameter(powers, "idd2p12"); + config.memSpec->iDD2N = queryDoubleParameter(powers, "idd2n"); + config.memSpec->iDD2N2 = queryDoubleParameter(powers, "idd2n2"); + config.memSpec->iDD3P0 = queryDoubleParameter(powers, "idd3p0"); + config.memSpec->iDD3P02 = queryDoubleParameter(powers, "idd3p02"); + config.memSpec->iDD3P1 = queryDoubleParameter(powers, "idd3p1"); + config.memSpec->iDD3P12 = queryDoubleParameter(powers, "idd3p12"); + config.memSpec->iDD3N = queryDoubleParameter(powers, "idd3n"); + config.memSpec->iDD3N2 = queryDoubleParameter(powers, "idd3n2"); + config.memSpec->iDD4R = queryDoubleParameter(powers, "idd4r"); + config.memSpec->iDD4R2 = queryDoubleParameter(powers, "idd4r2"); + config.memSpec->iDD4W = queryDoubleParameter(powers, "idd4w"); + config.memSpec->iDD4W2 = queryDoubleParameter(powers, "idd4w2"); + config.memSpec->iDD5 = queryDoubleParameter(powers, "idd5"); + config.memSpec->iDD52 = queryDoubleParameter(powers, "idd52"); + config.memSpec->iDD6 = queryDoubleParameter(powers, "idd6"); + config.memSpec->iDD62 = queryDoubleParameter(powers, "idd62"); + config.memSpec->vDD = queryDoubleParameter(powers, "vdd"); + config.memSpec->vDD2 = queryDoubleParameter(powers, "vdd2"); } diff --git a/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.h b/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.h index c4b77530..d7a12c57 100644 --- a/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.h +++ b/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.h @@ -65,8 +65,9 @@ private: static void loadConfig(Configuration &config, tinyxml2::XMLElement *configNode); static void loadConfigFromUri(Configuration &config, std::string uri, std::string first_element); - - //specific loader + // Loads common config of DRAMs + static void loadCommons(Configuration &config, tinyxml2::XMLElement *memspec); + // Load specific config static void loadDDR3(Configuration &config, tinyxml2::XMLElement *memspec); static void loadDDR4(Configuration &config, tinyxml2::XMLElement *memspec); static void loadLPDDR4(Configuration &config, tinyxml2::XMLElement *memspec); diff --git a/DRAMSys/library/src/controller/core/configuration/MemSpec.h b/DRAMSys/library/src/controller/core/configuration/MemSpec.h index 00a48073..fc4fb576 100644 --- a/DRAMSys/library/src/controller/core/configuration/MemSpec.h +++ b/DRAMSys/library/src/controller/core/configuration/MemSpec.h @@ -56,11 +56,6 @@ struct RefreshTiming struct MemSpec { - MemSpec() - { - //default DDR4 - } - const std::vector &getBanks() const { static std::vector banks; @@ -170,34 +165,22 @@ struct MemSpec struct MemSpecDDR3 : public MemSpec { - MemSpecDDR3() - { - std::cout << "Generated MemSpecDDR3" << std::endl; - } + }; struct MemSpecDDR4 : public MemSpec { - MemSpecDDR4() - { - std::cout << "Generated MemSpecDDR4" << std::endl; - } + }; struct MemSpecWideIO : public MemSpec { - MemSpecWideIO() - { - std::cout << "Generated MemSpecWideIO" << std::endl; - } + }; struct MemSpecLPDDR4 : public MemSpec { - MemSpecLPDDR4() - { - std::cout << "Generated MemSpecLPDDR4" << std::endl; - } + }; #endif // MEMSPEC_H diff --git a/DRAMSys/library/src/controller/core/refresh/RGR.cpp b/DRAMSys/library/src/controller/core/refresh/RGR.cpp index e7f5b652..f5cea5d0 100644 --- a/DRAMSys/library/src/controller/core/refresh/RGR.cpp +++ b/DRAMSys/library/src/controller/core/refresh/RGR.cpp @@ -46,19 +46,19 @@ using namespace std; RGR::RGR(sc_module_name, ControllerCore &ctrlcore) : ccore(ctrlcore), - timing(ctrlcore.config.memSpec.refreshTimings[ccore.getBanks()[0]]) + timing(ctrlcore.config.memSpec->refreshTimings[ccore.getBanks()[0]]) { fmb = ccore.config.ControllerCoreRefForceMaxPostponeBurst; bwl = ccore.config.BankwiseLogic; ri = ccore.config.getRowInc(); - auto nr = ccore.config.memSpec.NumberOfRows; + auto nr = ccore.config.memSpec->NumberOfRows; auto nar = ccore.config.getNumAR(); auto m = ccore.config.getRefMode(); rpr = (nr / m) / nar; assert(rpr > 0); tREFIx = timing.tREFI / m; trp = ccore.config.getTrpb(); - trcd = ccore.config.memSpec.tRCD; + trcd = ccore.config.memSpec->tRCD; postponeEnabled = ccore.config.ControllerCoreRefEnablePostpone; pullInEnabled = ccore.config.ControllerCoreRefEnablePullIn; maxpostpone = ccore.config.ControllerCoreRefMaxPostponed * m; @@ -73,7 +73,7 @@ RGR::RGR(sc_module_name, ControllerCore &ctrlcore) : ccore(ctrlcore), } #if INITIAL_DISPLACEMENT == TRUE if (bwl) { - auto nbs = ccore.config.memSpec.NumberOfBanks; + auto nbs = ccore.config.memSpec->NumberOfBanks; for (Bank b : ccore.getBanks()) { nextPlannedRefreshs[b] = b.ID() * tREFIx / nbs; } diff --git a/DRAMSys/library/src/controller/core/refresh/RefreshManager.cpp b/DRAMSys/library/src/controller/core/refresh/RefreshManager.cpp index 8b4981ec..b088ca97 100644 --- a/DRAMSys/library/src/controller/core/refresh/RefreshManager.cpp +++ b/DRAMSys/library/src/controller/core/refresh/RefreshManager.cpp @@ -46,7 +46,7 @@ using namespace tlm; RefreshManager::RefreshManager(sc_module_name, ControllerCore &controller) : controllerCore(controller), - timing(controller.config.memSpec.refreshTimings[Bank(0)]) + timing(controller.config.memSpec->refreshTimings[Bank(0)]) { auto m = controllerCore.config.getRefMode(); tREFIx = timing.tREFI / m; @@ -159,7 +159,7 @@ void RefreshManager::scheduleRefresh(tlm::tlm_generic_payload &payload, pre = doRefresh(payload, time); nrt = tRFCx; if (pre) - nrt += controllerCore.config.memSpec.tRP; + nrt += controllerCore.config.memSpec->tRP; nextRefTiming = nrt; nextState = ST_PULLIN; } else { @@ -175,7 +175,7 @@ void RefreshManager::scheduleRefresh(tlm::tlm_generic_payload &payload, pre = doRefresh(payload, time); nrt = tRFCx; if (pre) - nrt += controllerCore.config.memSpec.tRP; + nrt += controllerCore.config.memSpec->tRP; nextRefTiming = nrt; nextState = ST_PULLIN; } else { @@ -220,7 +220,7 @@ void RefreshManager::scheduleRefresh(tlm::tlm_generic_payload &payload, } else { nrt = tRFCx; if (pre) - nrt += controllerCore.config.memSpec.tRP; + nrt += controllerCore.config.memSpec->tRP; nextRefTiming = nrt; nextState = ST_BURST; } diff --git a/DRAMSys/library/src/controller/core/refresh/RefreshManagerBankwise.cpp b/DRAMSys/library/src/controller/core/refresh/RefreshManagerBankwise.cpp index a496ab8e..c53f779b 100644 --- a/DRAMSys/library/src/controller/core/refresh/RefreshManagerBankwise.cpp +++ b/DRAMSys/library/src/controller/core/refresh/RefreshManagerBankwise.cpp @@ -44,7 +44,7 @@ using namespace std; RefreshManagerBankwise::RefreshManagerBankwise(sc_module_name, ControllerCore &controller) : controllerCore(controller), - timing(controller.config.memSpec.refreshTimings[Bank(0)]) + timing(controller.config.memSpec->refreshTimings[Bank(0)]) { auto m = controllerCore.config.getRefMode(); tREFIx = timing.tREFI / m; @@ -146,7 +146,7 @@ void RefreshManagerBankwise::scheduleRefresh(tlm::tlm_generic_payload &payload, pre = doRefresh(payload, time); nrt = tRFCx; if (pre) - nrt += controllerCore.config.memSpec.tRP; + nrt += controllerCore.config.memSpec->tRP; nextRefTiming = nrt; nextState[bank] = ST_PULLIN; } else { @@ -162,7 +162,7 @@ void RefreshManagerBankwise::scheduleRefresh(tlm::tlm_generic_payload &payload, pre = doRefresh(payload, time); nrt = tRFCx; if (pre) - nrt += controllerCore.config.memSpec.tRP; + nrt += controllerCore.config.memSpec->tRP; nextRefTiming = nrt; nextState[bank] = ST_PULLIN; } else { @@ -208,7 +208,7 @@ void RefreshManagerBankwise::scheduleRefresh(tlm::tlm_generic_payload &payload, } else { nrt = tRFCx; if (pre) - nrt += controllerCore.config.memSpec.tRP; + nrt += controllerCore.config.memSpec->tRP; nextRefTiming = nrt; nextState[bank] = ST_BURST; } diff --git a/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.cpp b/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.cpp index 2945cc74..4207b9ff 100644 --- a/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.cpp @@ -127,13 +127,13 @@ TimeInterval ScheduledCommand::getIntervalOnDataStrobe() const || getCommand() == Command::Write || getCommand() == Command::WriteA); - MemSpec &timings = Configuration::getInstance().memSpec; + MemSpec *timings = Configuration::getInstance().memSpec; if (getCommand() == Command::Read || getCommand() == Command::ReadA) { - return TimeInterval(getStart() + timings.tRL, - getStart() + timings.tRL + getReadAccessTime()); + return TimeInterval(getStart() + timings->tRL, + getStart() + timings->tRL + getReadAccessTime()); } else { - return TimeInterval(getStart() + timings.tWL - timings.clk / 2, - getStart() + timings.tWL + getWriteAccessTime() - timings.clk / 2); + return TimeInterval(getStart() + timings->tWL - timings->clk / 2, + getStart() + timings->tWL + getWriteAccessTime() - timings->clk / 2); } } diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/ActBChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/ActBChecker.cpp index 55edd9a9..16557602 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/ActBChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/ActBChecker.cpp @@ -53,27 +53,27 @@ void ActBChecker::delayToSatisfyConstraints(ScheduledCommand &cmd) const Configuration::getInstance().getTrpb()); } else if (lcb.getCommand() == Command::Precharge || lcb.getCommand() == Command::PrechargeAll) { - cmd.establishMinDistanceFromStart(lcb.getStart(), config.memSpec.tRP); + cmd.establishMinDistanceFromStart(lcb.getStart(), config.memSpec->tRP); } else if (lcb.getCommand() == Command::ReadA) { cmd.establishMinDistanceFromStart(lcb.getStart(), - config.memSpec.tRTP + config.memSpec.tRP); + config.memSpec->tRTP + config.memSpec->tRP); } else if (lcb.getCommand() == Command::WriteA) { cmd.establishMinDistanceFromStart(lcb.getStart(), - config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR + - config.memSpec.tRP); + config.memSpec->tWL + getWriteAccessTime() + config.memSpec->tWR + + config.memSpec->tRP); } else if (lcb.getCommand() == Command::AutoRefresh) { auto m = Configuration::getInstance().getRefMode(); if (m == 4) - cmd.establishMinDistanceFromStart(lcb.getStart(), config.memSpec.tRFC4); + cmd.establishMinDistanceFromStart(lcb.getStart(), config.memSpec->tRFC4); else if (m == 2) - cmd.establishMinDistanceFromStart(lcb.getStart(), config.memSpec.tRFC2); + cmd.establishMinDistanceFromStart(lcb.getStart(), config.memSpec->tRFC2); else - cmd.establishMinDistanceFromStart(lcb.getStart(), config.memSpec.tRFC); + cmd.establishMinDistanceFromStart(lcb.getStart(), config.memSpec->tRFC); } else if (lcb.getCommand() == Command::PDNPX || lcb.getCommand() == Command::PDNAX) { - cmd.establishMinDistanceFromStart(lcb.getStart(), config.memSpec.tXP); + cmd.establishMinDistanceFromStart(lcb.getStart(), config.memSpec->tXP); } else if (lcb.getCommand() == Command::SREFX) { - cmd.establishMinDistanceFromStart(lcb.getStart(), config.memSpec.tXSR); + cmd.establishMinDistanceFromStart(lcb.getStart(), config.memSpec->tXSR); } else { reportFatal("ActB Checker", "ActB can not follow " + commandToString(lcb.getCommand())); @@ -81,13 +81,13 @@ void ActBChecker::delayToSatisfyConstraints(ScheduledCommand &cmd) const } ScheduledCommand lc; if ((lc = state.getLastCommand(Command::PrechargeAll)).isValidCommand()) { - cmd.establishMinDistanceFromStart(lc.getStart(), config.memSpec.tRP); + cmd.establishMinDistanceFromStart(lc.getStart(), config.memSpec->tRP); } delay_to_satisfy_activateToActivate_sameBank(cmd); while (!(state.bus.isFree(cmd.getStart()) && satsfies_activateToActivate_differentBank(cmd) && satisfies_nActivateWindow(cmd))) { - cmd.delayStart(config.memSpec.clk); + cmd.delayStart(config.memSpec->clk); } } @@ -97,7 +97,7 @@ void ActBChecker::delay_to_satisfy_activateToActivate_sameBank( ScheduledCommand lastActOnBank = state.getLastCommand(Command::Activate, cmd.getBank()); if (lastActOnBank.isValidCommand()) { - cmd.establishMinDistanceFromStart(lastActOnBank.getStart(), config.memSpec.tRC); + cmd.establishMinDistanceFromStart(lastActOnBank.getStart(), config.memSpec->tRC); } ScheduledCommand lastActBOnBank = state.getLastCommand(Command::ActB, cmd.getBank()); @@ -121,7 +121,7 @@ bool ActBChecker::satsfies_activateToActivate_differentBank( } for (auto act : state.lastActivates) { sc_time t = act.first, tRRD = (cmd.getBankGroup() == act.second.getBankGroup() ? - config.memSpec.tRRD_L : config.memSpec.tRRD_S); + config.memSpec->tRRD_L : config.memSpec->tRRD_S); if ((t < cmd.getStart() && cmd.getStart() - t < tRRD) || (cmd.getStart() <= t && t - cmd.getStart() < tRRD)) { return false; @@ -132,11 +132,11 @@ bool ActBChecker::satsfies_activateToActivate_differentBank( bool ActBChecker::satisfies_nActivateWindow(ScheduledCommand &cmd) const { - if (state.lastActivatesB.size() >= config.memSpec.nActivate) { + if (state.lastActivatesB.size() >= config.memSpec->nActivate) { maplastActivates = state.lastActivatesB; lastActivates.emplace(cmd.getStart(), cmd); auto upper = lastActivates.begin(); - advance(upper, config.memSpec.nActivate); + advance(upper, config.memSpec->nActivate); auto lower = lastActivates.begin(); while (upper != lastActivates.end()) { if (upper->first - lower->first < Configuration::getInstance().getTfawb()) { diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/ActivateChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/ActivateChecker.cpp index 18236ba3..f2bb8033 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/ActivateChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/ActivateChecker.cpp @@ -56,32 +56,32 @@ void ActivateChecker::delayToSatisfyConstraints(ScheduledCommand &command) const || lastCommandOnBank.getCommand() == Command::Precharge || lastCommandOnBank.getCommand() == Command::PrechargeAll) { command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), - config.memSpec.tRP); + config.memSpec->tRP); } else if (lastCommandOnBank.getCommand() == Command::ReadA) { command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), - config.memSpec.tRTP + config.memSpec.tRP); + config.memSpec->tRTP + config.memSpec->tRP); } else if (lastCommandOnBank.getCommand() == Command::WriteA) { command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), - config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR + - config.memSpec.tRP); + config.memSpec->tWL + getWriteAccessTime() + config.memSpec->tWR + + config.memSpec->tRP); } else if (lastCommandOnBank.getCommand() == Command::AutoRefresh) { auto m = Configuration::getInstance().getRefMode(); if (m == 4) command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), - config.memSpec.tRFC4); + config.memSpec->tRFC4); else if (m == 2) command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), - config.memSpec.tRFC2); + config.memSpec->tRFC2); else command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), - config.memSpec.tRFC); + config.memSpec->tRFC); } else if (lastCommandOnBank.getCommand() == Command::PDNPX || lastCommandOnBank.getCommand() == Command::PDNAX) { command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), - config.memSpec.tXP); + config.memSpec->tXP); } else if (lastCommandOnBank.getCommand() == Command::SREFX) { command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), - config.memSpec.tXSR); + config.memSpec->tXSR); } else reportFatal("Activate Checker", "Activate can not follow " + commandToString(lastCommandOnBank.getCommand())); @@ -92,7 +92,7 @@ void ActivateChecker::delayToSatisfyConstraints(ScheduledCommand &command) const while (!(state.bus.isFree(command.getStart()) && satsfies_activateToActivate_differentBank(command) && satisfies_nActivateWindow(command))) { - command.delayStart(config.memSpec.clk); + command.delayStart(config.memSpec->clk); } } @@ -104,14 +104,14 @@ void ActivateChecker::delay_to_satisfy_activateToActivate_sameBank( command.getBank()); if (lastActivateOnBank.isValidCommand()) { command.establishMinDistanceFromStart(lastActivateOnBank.getStart(), - config.memSpec.tRC); + config.memSpec->tRC); } ScheduledCommand lastActBOnBank = state.getLastCommand(Command::ActB, command.getBank()); if (lastActBOnBank.isValidCommand()) { command.establishMinDistanceFromStart(lastActivateOnBank.getStart(), - config.memSpec.tRC); + config.memSpec->tRC); } } @@ -121,7 +121,7 @@ bool ActivateChecker::satsfies_activateToActivate_differentBank( for (auto act : state.lastActivates) { sc_time time = act.first; sc_time tRRD = (command.getBankGroup() == act.second.getBankGroup()) ? - config.memSpec.tRRD_L : config.memSpec.tRRD_S; + config.memSpec->tRRD_L : config.memSpec->tRRD_S; if ((time < command.getStart() && command.getStart() - time < tRRD) || (command.getStart() <= time && time - command.getStart() < tRRD)) @@ -137,15 +137,15 @@ bool ActivateChecker::satisfies_nActivateWindow(ScheduledCommand &command) const * command in a copied set (not necessarily the last in time), * and check if the n-act constraint holds for the whole set. */ - if (state.lastActivates.size() >= config.memSpec.nActivate) { + if (state.lastActivates.size() >= config.memSpec->nActivate) { map lastActivates = state.lastActivates; lastActivates.emplace(command.getStart(), command); auto upper = lastActivates.begin(); - advance(upper, config.memSpec.nActivate); + advance(upper, config.memSpec->nActivate); auto lower = lastActivates.begin(); while (upper != lastActivates.end()) { - if (upper->first - lower->first < config.memSpec.tNAW) + if (upper->first - lower->first < config.memSpec->tNAW) return false; ++upper; ++lower; diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/PowerDownChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/PowerDownChecker.cpp index 7a430ac6..723c74ec 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/PowerDownChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/PowerDownChecker.cpp @@ -47,26 +47,26 @@ sc_time PowerDownChecker::getTimeConstraintToEnterPowerDown(Command lastCmd, sc_time constraint; if (lastCmd == Command::Read || lastCmd == Command::ReadA) { - constraint = config.memSpec.tRL + getReadAccessTime() + config.memSpec.clk; + constraint = config.memSpec->tRL + getReadAccessTime() + config.memSpec->clk; } else if (lastCmd == Command::Write) { - constraint = config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR; + constraint = config.memSpec->tWL + getWriteAccessTime() + config.memSpec->tWR; } else if (lastCmd == Command::WriteA) { - constraint = config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR + - config.memSpec.clk; + constraint = config.memSpec->tWL + getWriteAccessTime() + config.memSpec->tWR + + config.memSpec->clk; } else if (lastCmd == Command::AutoRefresh) { auto m = Configuration::getInstance().getRefMode(); if (m == 4) - constraint = config.memSpec.tRFC4; + constraint = config.memSpec->tRFC4; else if (m == 2) - constraint = config.memSpec.tRFC2; + constraint = config.memSpec->tRFC2; else - constraint = config.memSpec.tRFC; + constraint = config.memSpec->tRFC; } else if (lastCmd == Command::PDNPX || lastCmd == Command::PDNAX) { - constraint = config.memSpec.tXP; + constraint = config.memSpec->tXP; } else if (lastCmd == Command::SREFX) { - constraint = config.memSpec.tXSR; + constraint = config.memSpec->tXSR; } else if (lastCmd == Command::Precharge || lastCmd == Command::PrechargeAll) { - constraint = config.memSpec.tRP; + constraint = config.memSpec->tRP; } else { reportFatal("Powerdown checker", commandToString(pdnCmd) + " can not follow " + commandToString(lastCmd)); @@ -117,17 +117,17 @@ const } else if (pdnCmd == Command::PDNAX) { // Leaving Active Power Down - timeConstraint = config.memSpec.tCKE; + timeConstraint = config.memSpec->tCKE; command.establishMinDistanceFromStart(state.getLastCommand(Command::PDNA, bank).getStart(), timeConstraint); } else if (pdnCmd == Command::PDNPX) { // Leaving Precharge Power Down - timeConstraint = config.memSpec.tCKE; + timeConstraint = config.memSpec->tCKE; command.establishMinDistanceFromStart(state.getLastCommand(Command::PDNP, bank).getStart(), timeConstraint); } else if (pdnCmd == Command::SREFX) { // Leaving Self Refresh - timeConstraint = config.memSpec.tCKESR; + timeConstraint = config.memSpec->tCKESR; command.establishMinDistanceFromStart(state.getLastCommand(Command::SREF, bank).getStart(), timeConstraint); } diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/PreBChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/PreBChecker.cpp index f559bf38..44e23882 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/PreBChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/PreBChecker.cpp @@ -43,21 +43,21 @@ void PreBChecker::delayToSatisfyConstraints(ScheduledCommand &cmd) const cmd.establishMinDistanceFromStart(lastCmd.getStart(), Configuration::getInstance().getTrpb()); } else if (lastCmd.getCommand() == Command::Precharge) { - cmd.establishMinDistanceFromStart(lastCmd.getStart(), config.memSpec.tRP); + cmd.establishMinDistanceFromStart(lastCmd.getStart(), config.memSpec->tRP); } else if (lastCmd.getCommand() == Command::PrechargeAll) { - cmd.establishMinDistanceFromStart(lastCmd.getStart(), config.memSpec.tRP); + cmd.establishMinDistanceFromStart(lastCmd.getStart(), config.memSpec->tRP); } else if (lastCmd.getCommand() == Command::ActB) { cmd.establishMinDistanceFromStart(lastCmd.getStart(), - config.memSpec.tRCD); // XXX: trcd is less than the NEW! trasb! ok! + config.memSpec->tRCD); // XXX: trcd is less than the NEW! trasb! ok! } else if (lastCmd.getCommand() == Command::Activate) { - cmd.establishMinDistanceFromStart(lastCmd.getStart(), config.memSpec.tRCD); + cmd.establishMinDistanceFromStart(lastCmd.getStart(), config.memSpec->tRCD); } else if (lastCmd.getCommand() == Command::Read) { - cmd.establishMinDistanceFromStart(lastCmd.getStart(), config.memSpec.tRTP); + cmd.establishMinDistanceFromStart(lastCmd.getStart(), config.memSpec->tRTP); } else if (lastCmd.getCommand() == Command::Write) { cmd.establishMinDistanceFromStart(lastCmd.getStart(), - config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR); + config.memSpec->tWL + getWriteAccessTime() + config.memSpec->tWR); } else if (lastCmd.getCommand() == Command::PDNAX) { - cmd.establishMinDistanceFromStart(lastCmd.getStart(), config.memSpec.tXP); + cmd.establishMinDistanceFromStart(lastCmd.getStart(), config.memSpec->tXP); } else { reportFatal("PreB Checker", "PreB can not follow " + commandToString(lastCmd.getCommand())); @@ -65,11 +65,11 @@ void PreBChecker::delayToSatisfyConstraints(ScheduledCommand &cmd) const } ScheduledCommand lc; if ((lc = state.getLastCommand(Command::PrechargeAll)).isValidCommand()) { - cmd.establishMinDistanceFromStart(lc.getStart(), config.memSpec.tRP); + cmd.establishMinDistanceFromStart(lc.getStart(), config.memSpec->tRP); } if ((lc = state.getLastCommand(Command::Activate, cmd.getBank())).isValidCommand()) { - cmd.establishMinDistanceFromStart(lc.getStart(), config.memSpec.tRAS); + cmd.establishMinDistanceFromStart(lc.getStart(), config.memSpec->tRAS); } if ((lc = state.getLastCommand(Command::ActB, cmd.getBank())).isValidCommand()) { diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/PrechargeAllChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/PrechargeAllChecker.cpp index f666408d..f6ee06d9 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/PrechargeAllChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/PrechargeAllChecker.cpp @@ -45,48 +45,48 @@ const sc_assert(command.getCommand() == Command::PrechargeAll); // Consider all banks for the constraints, since precharge all command is supposed to happen at the same time on all banks - for (unsigned int bank = 0; bank < config.memSpec.NumberOfBanks; ++bank) { + for (unsigned int bank = 0; bank < config.memSpec->NumberOfBanks; ++bank) { ScheduledCommand lastCommand = state.getLastScheduledCommand(Bank(bank)); if (lastCommand.isValidCommand()) { if (lastCommand.getCommand() == Command::Precharge || lastCommand.getCommand() == Command::PreB) { command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tRP); + config.memSpec->tRP); } else if (lastCommand.getCommand() == Command::Activate || lastCommand.getCommand() == Command::ActB) { command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tRCD); + config.memSpec->tRCD); } else if (lastCommand.getCommand() == Command::Read) { command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tRTP); + config.memSpec->tRTP); } else if (lastCommand.getCommand() == Command::ReadA) { command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tRTP + config.memSpec.tRP); + config.memSpec->tRTP + config.memSpec->tRP); } else if (lastCommand.getCommand() == Command::Write) { command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR); + config.memSpec->tWL + getWriteAccessTime() + config.memSpec->tWR); } else if (lastCommand.getCommand() == Command::WriteA) { command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR + - config.memSpec.tRP); + config.memSpec->tWL + getWriteAccessTime() + config.memSpec->tWR + + config.memSpec->tRP); } else if (lastCommand.getCommand() == Command::AutoRefresh) { auto m = Configuration::getInstance().getRefMode(); if (m == 4) command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tRFC4); + config.memSpec->tRFC4); else if (m == 2) command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tRFC2); + config.memSpec->tRFC2); else command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tRFC); + config.memSpec->tRFC); } else if (lastCommand.getCommand() == Command::PDNAX || lastCommand.getCommand() == Command::PDNPX) { command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tXP); + config.memSpec->tXP); } else if (lastCommand.getCommand() == Command::SREFX) { command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tXSR); + config.memSpec->tXSR); } else reportFatal("Precharge All Checker", "Precharge All can not follow " + commandToString(lastCommand.getCommand())); @@ -97,7 +97,7 @@ const command.getBank()); if (lastActivate.isValidCommand()) { command.establishMinDistanceFromStart(lastActivate.getStart(), - config.memSpec.tRAS); + config.memSpec->tRAS); } state.bus.moveCommandToNextFreeSlot(command); diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/PrechargeChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/PrechargeChecker.cpp index 6767be1f..75a8ebdc 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/PrechargeChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/PrechargeChecker.cpp @@ -52,23 +52,23 @@ const if (lastCommand.getCommand() == Command::Precharge || lastCommand.getCommand() == Command::PreB) { command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tRP); + config.memSpec->tRP); } else if (lastCommand.getCommand() == Command::Activate || lastCommand.getCommand() == Command::ActB) { command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tRCD); + config.memSpec->tRCD); } else if (lastCommand.getCommand() == Command::Read) { command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tRTP); + config.memSpec->tRTP); } else if (lastCommand.getCommand() == Command::Write) { command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR); + config.memSpec->tWL + getWriteAccessTime() + config.memSpec->tWR); } else if (lastCommand.getCommand() == Command::PDNAX) { command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tXP); + config.memSpec->tXP); } else reportFatal("Precharge Checker", "Precharge can not follow " + commandToString(lastCommand.getCommand())); @@ -78,7 +78,7 @@ const command.getBank()); if (lastActivate.isValidCommand()) { command.establishMinDistanceFromStart(lastActivate.getStart(), - config.memSpec.tRAS); + config.memSpec->tRAS); } state.bus.moveCommandToNextFreeSlot(command); diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/ReadChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/ReadChecker.cpp index 048f5cd5..06a121a6 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/ReadChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/ReadChecker.cpp @@ -52,7 +52,7 @@ void ReadChecker::delayToSatisfyConstraints(ScheduledCommand &command) const if (lastCommand.getCommand() == Command::Activate || lastCommand.getCommand() == Command::ActB) { command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tRCD); + config.memSpec->tRCD); } else if (lastCommand.getCommand() == Command::Read) { command.establishMinDistanceFromStart(lastCommand.getStart(), ReadChecker::readToRead(lastCommand, command)); @@ -62,14 +62,14 @@ void ReadChecker::delayToSatisfyConstraints(ScheduledCommand &command) const } else if (lastCommand.getCommand() == Command::PDNPX || lastCommand.getCommand() == Command::PDNAX) { command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tXP); + config.memSpec->tXP); } else reportFatal("Read Checker", "Read can not follow " + commandToString(lastCommand.getCommand())); } while (!state.bus.isFree(command.getStart()) || collidesOnDataStrobe(command)) { - command.delayStart(config.memSpec.clk); + command.delayStart(config.memSpec->clk); } } @@ -112,7 +112,7 @@ void ReadChecker::delayToSatisfyDLL(ScheduledCommand &read) const read.getBank()); if (lastSREFX.isValidCommand()) read.establishMinDistanceFromStart(lastSREFX.getStart(), - config.memSpec.tXSRDLL); + config.memSpec->tXSRDLL); } sc_time ReadChecker::readToRead(ScheduledCommand &firstRead, @@ -123,9 +123,9 @@ sc_time ReadChecker::readToRead(ScheduledCommand &firstRead, sc_assert(secondRead.getCommand() == Command::Read || secondRead.getCommand() == Command::ReadA); - MemSpec &config = Configuration::getInstance().memSpec; + MemSpec *config = Configuration::getInstance().memSpec; sc_time tCCD = (firstRead.getBankGroup() == secondRead.getBankGroup()) ? - config.tCCD_L : config.tCCD_S; + config->tCCD_L : config->tCCD_S; return max(tCCD, getReadAccessTime()); } @@ -137,9 +137,9 @@ sc_time ReadChecker::writeToRead(ScheduledCommand &write, sc_assert(write.getCommand() == Command::Write || write.getCommand() == Command::WriteA); - MemSpec &config = Configuration::getInstance().memSpec; - sc_time tWTR = (write.getBankGroup() == read.getBankGroup()) ? config.tWTR_L : - config.tWTR_S; - return config.tWL + getWriteAccessTime() + tWTR; + MemSpec *config = Configuration::getInstance().memSpec; + sc_time tWTR = (write.getBankGroup() == read.getBankGroup()) ? config->tWTR_L : + config->tWTR_S; + return config->tWL + getWriteAccessTime() + tWTR; } diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/RefreshChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/RefreshChecker.cpp index aad23f4a..eea8f763 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/RefreshChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/RefreshChecker.cpp @@ -50,53 +50,53 @@ void RefreshChecker::delayToSatisfyConstraints(ScheduledCommand &command) const if (lastCommandOnBank.getCommand() == Command::Precharge || lastCommandOnBank.getCommand() == Command::PrechargeAll) { command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), - config.memSpec.tRP); + config.memSpec->tRP); } else if (lastCommandOnBank.getCommand() == Command::ReadA) { command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), - config.memSpec.tRTP + config.memSpec.tRP); + config.memSpec->tRTP + config.memSpec->tRP); } else if (lastCommandOnBank.getCommand() == Command::WriteA) { command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), - config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR + - config.memSpec.tRP); + config.memSpec->tWL + getWriteAccessTime() + config.memSpec->tWR + + config.memSpec->tRP); } else if (lastCommandOnBank.getCommand() == Command::PDNPX || lastCommandOnBank.getCommand() == Command::PDNAX) { command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), - config.memSpec.tXP); + config.memSpec->tXP); } else if (lastCommandOnBank.getCommand() == Command::SREFX) { command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), - config.memSpec.tXSR); + config.memSpec->tXSR); } else if (lastCommandOnBank.getCommand() == Command::AutoRefresh) { } else reportFatal("Refresh Checker", "Refresh can not follow " + commandToString(lastCommandOnBank.getCommand())); } } else { - for (unsigned int bank = 0; bank < config.memSpec.NumberOfBanks; ++bank) { + for (unsigned int bank = 0; bank < config.memSpec->NumberOfBanks; ++bank) { ScheduledCommand lastCommand = state.getLastScheduledCommand(Bank(bank)); if (lastCommand.isValidCommand()) { if (lastCommand.getCommand() == Command::Precharge || lastCommand.getCommand() == Command::PrechargeAll || lastCommand.getCommand() == Command::PreB) { command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tRP); + config.memSpec->tRP); } else if (lastCommand.getCommand() == Command::Activate || lastCommand.getCommand() == Command::ActB) { command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tRCD); + config.memSpec->tRCD); } else if (lastCommand.getCommand() == Command::ReadA) { command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tRTP + config.memSpec.tRP); + config.memSpec->tRTP + config.memSpec->tRP); } else if (lastCommand.getCommand() == Command::WriteA) { command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR + - config.memSpec.tRP); + config.memSpec->tWL + getWriteAccessTime() + config.memSpec->tWR + + config.memSpec->tRP); } else if (lastCommand.getCommand() == Command::PDNAX || lastCommand.getCommand() == Command::PDNPX) { command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tXP); + config.memSpec->tXP); } else if (lastCommand.getCommand() == Command::SREFX) { command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tXSR); + config.memSpec->tXSR); } else if (lastCommand.getCommand() == Command::AutoRefresh) { } else reportFatal("Refresh Checker", diff --git a/DRAMSys/library/src/controller/core/scheduling/checker/WriteChecker.cpp b/DRAMSys/library/src/controller/core/scheduling/checker/WriteChecker.cpp index b2aed2d2..38eafdaa 100644 --- a/DRAMSys/library/src/controller/core/scheduling/checker/WriteChecker.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/checker/WriteChecker.cpp @@ -52,7 +52,7 @@ void WriteChecker::delayToSatisfyConstraints(ScheduledCommand &command) const if (lastCommand.getCommand() == Command::Activate || lastCommand.getCommand() == Command::ActB) { command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tRCD); + config.memSpec->tRCD); } else if (lastCommand.getCommand() == Command::Read) { command.establishMinDistanceFromStart(lastCommand.getStart(), WriteChecker::readToWrite(lastCommand, command)); @@ -62,14 +62,14 @@ void WriteChecker::delayToSatisfyConstraints(ScheduledCommand &command) const } else if (lastCommand.getCommand() == Command::PDNPX || lastCommand.getCommand() == Command::PDNAX) { command.establishMinDistanceFromStart(lastCommand.getStart(), - config.memSpec.tXP); + config.memSpec->tXP); } else reportFatal("Write Checker", "Write can not follow " + commandToString(lastCommand.getCommand())); } while (!state.bus.isFree(command.getStart()) || collidesOnDataStrobe(command)) { - command.delayStart(config.memSpec.clk); + command.delayStart(config.memSpec->clk); } } @@ -114,9 +114,9 @@ sc_time WriteChecker::writeToWrite(ScheduledCommand &firstWrite, sc_assert(secondWrite.getCommand() == Command::Write || secondWrite.getCommand() == Command::WriteA); - MemSpec &config = Configuration::getInstance().memSpec; + MemSpec *config = Configuration::getInstance().memSpec; sc_time tCCD = (firstWrite.getBankGroup() == secondWrite.getBankGroup()) ? - config.tCCD_L : config.tCCD_S; + config->tCCD_L : config->tCCD_S; return max(tCCD, getWriteAccessTime()); } @@ -128,7 +128,7 @@ sc_time WriteChecker::readToWrite(ScheduledCommand &read __attribute__(( sc_assert(write.getCommand() == Command::Write || write.getCommand() == Command::WriteA); - MemSpec &config = Configuration::getInstance().memSpec; - return config.tRL + getReadAccessTime() - config.tWL + config.clk * 2; + MemSpec *config = Configuration::getInstance().memSpec; + return config->tRL + getReadAccessTime() - config->tWL + config->clk * 2; } diff --git a/DRAMSys/library/src/controller/core/timingCalculations.cpp b/DRAMSys/library/src/controller/core/timingCalculations.cpp index 2f4b65cb..077e5d22 100644 --- a/DRAMSys/library/src/controller/core/timingCalculations.cpp +++ b/DRAMSys/library/src/controller/core/timingCalculations.cpp @@ -59,7 +59,7 @@ const sc_time FrequencyToClk(double frequencyMhz) const sc_time clkAlign(sc_time time, Alignment alignment) { - sc_time clk = Configuration::getInstance().memSpec.clk; + sc_time clk = Configuration::getInstance().memSpec->clk; if (alignment == UP) return ceil(time / clk) * clk; else @@ -69,39 +69,39 @@ const sc_time clkAlign(sc_time time, Alignment alignment) // Returns the execution time for commands that have a fixed execution time sc_time getExecutionTime(Command command, tlm::tlm_generic_payload &payload) { - MemSpec &config = Configuration::getInstance().memSpec; + MemSpec *config = Configuration::getInstance().memSpec; if (command == Command::PreB) { return Configuration::getInstance().getTrpb(); } else if (command == Command::Precharge || command == Command::PrechargeAll) { - return config.tRP; + return config->tRP; } else if (command == Command::ActB) { - return config.tRCD; + return config->tRCD; } else if (command == Command::Activate) { - return config.tRCD; + return config->tRCD; } else if (command == Command::Read) { - return config.tRL + getReadAccessTime(); + return config->tRL + getReadAccessTime(); } else if (command == Command::ReadA) { - return config.tRTP + config.tRP; + return config->tRTP + config->tRP; } else if (command == Command::Write) { - return config.tWL + getWriteAccessTime(); + return config->tWL + getWriteAccessTime(); } else if (command == Command::WriteA) { - return config.tWL + getWriteAccessTime() + config.tWR + config.tRP; + return config->tWL + getWriteAccessTime() + config->tWR + config->tRP; } else if (command == Command::PrechargeAll) { - return config.tRP; + return config->tRP; } else if (command == Command::AutoRefresh) { if (Configuration::getInstance().getRefMode() == 4) - return getElementFromMap(config.refreshTimings, + return getElementFromMap(config->refreshTimings, DramExtension::getExtension(payload).getBank()).tRFC4; else if (Configuration::getInstance().getRefMode() == 2) - return getElementFromMap(config.refreshTimings, + return getElementFromMap(config->refreshTimings, DramExtension::getExtension(payload).getBank()).tRFC2; else - return getElementFromMap(config.refreshTimings, + return getElementFromMap(config->refreshTimings, DramExtension::getExtension(payload).getBank()).tRFC; } else if (command == Command::PDNAX || command == Command::PDNPX || command == Command::SREFX) { - return config.clk; + return config->clk; } else { SC_REPORT_FATAL("getExecutionTime", "command not known or command doesn't have a fixed execution time"); @@ -112,11 +112,11 @@ sc_time getExecutionTime(Command command, tlm::tlm_generic_payload &payload) // Returns the minimum execution time for commands that have a variable execution time sc_time getMinExecutionTimeForPowerDownCmd(Command command) { - MemSpec &config = Configuration::getInstance().memSpec; + MemSpec *config = Configuration::getInstance().memSpec; if (command == Command::PDNA || command == Command::PDNP) { - return config.tCKE; + return config->tCKE; } else if (command == Command::SREF) { - return config.tCKESR; + return config->tCKESR; } else { SC_REPORT_FATAL("getMinimalExecutionTime", "command is not know or command has a fixed execution time"); @@ -133,19 +133,19 @@ bool isClkAligned(sc_time time, sc_time clk) sc_time getReadAccessTime() { Configuration &config = Configuration::getInstance(); - return (config.memSpec.BurstLength / config.memSpec.DataRate) * - config.memSpec.clk; + return (config.memSpec->BurstLength / config.memSpec->DataRate) * + config.memSpec->clk; } sc_time getWriteAccessTime() { Configuration &config = Configuration::getInstance(); - if (config.memSpec.DataRate == 1) { - return config.memSpec.clk * (config.memSpec.BurstLength); + if (config.memSpec->DataRate == 1) { + return config.memSpec->clk * (config.memSpec->BurstLength); } else { - return config.memSpec.clk * (config.memSpec.BurstLength / - config.memSpec.DataRate); + return config.memSpec->clk * (config.memSpec->BurstLength / + config.memSpec->DataRate); } } diff --git a/DRAMSys/library/src/controller/scheduler/FrFcfsGrp.cpp b/DRAMSys/library/src/controller/scheduler/FrFcfsGrp.cpp index ef5d1bc1..3b41fd43 100644 --- a/DRAMSys/library/src/controller/scheduler/FrFcfsGrp.cpp +++ b/DRAMSys/library/src/controller/scheduler/FrFcfsGrp.cpp @@ -132,7 +132,7 @@ std::pair FrFcfsGrp::getNextRequest(Bank bank) // If nothing was found we check the other banks before we switch the mode: pair other(Command::NOP, NULL); - unsigned int B = Configuration::getInstance().memSpec.NumberOfBanks; + unsigned int B = Configuration::getInstance().memSpec->NumberOfBanks; for (unsigned int i = 1; i < B; i++) { Bank nextBank((bank.ID() + i) % B); @@ -175,7 +175,7 @@ unsigned int FrFcfsGrp::getNumberOfRequest(tlm::tlm_command cmd) { unsigned int numberOfRequests = 0; for (unsigned int i = 0; - i < Configuration::getInstance().memSpec.NumberOfBanks; + i < Configuration::getInstance().memSpec->NumberOfBanks; i++) { for (auto it = buffer[i].begin(); it != buffer[i].end(); it++) { gp *trans = *it; diff --git a/DRAMSys/library/src/controller/scheduler/Grp.cpp b/DRAMSys/library/src/controller/scheduler/Grp.cpp index aa6c49cf..cf4dffe2 100644 --- a/DRAMSys/library/src/controller/scheduler/Grp.cpp +++ b/DRAMSys/library/src/controller/scheduler/Grp.cpp @@ -118,7 +118,7 @@ std::pair Grp::getNextRequest(Bank bank) // If nothing was found we check the other banks before we switch the mode: pair other(Command::NOP, NULL); - unsigned int B = Configuration::getInstance().memSpec.NumberOfBanks; + unsigned int B = Configuration::getInstance().memSpec->NumberOfBanks; for (unsigned int i = 1; i < B; i++) { Bank nextBank((bank.ID() + i) % B); @@ -161,7 +161,7 @@ unsigned int Grp::getNumberOfRequest(tlm::tlm_command cmd) { unsigned int numberOfRequests = 0; for (unsigned int i = 0; - i < Configuration::getInstance().memSpec.NumberOfBanks; + i < Configuration::getInstance().memSpec->NumberOfBanks; i++) { for (auto it = buffer[i].begin(); it != buffer[i].end(); it++) { gp *trans = *it; diff --git a/DRAMSys/library/src/controller/scheduler/SMS.cpp b/DRAMSys/library/src/controller/scheduler/SMS.cpp index 42530571..f01267d7 100644 --- a/DRAMSys/library/src/controller/scheduler/SMS.cpp +++ b/DRAMSys/library/src/controller/scheduler/SMS.cpp @@ -46,7 +46,7 @@ std::pair SMS::getNextRequest(Bank bank) void SMS::batchScheduler() { - sc_time memClk = Configuration::getInstance().memSpec.clk; + sc_time memClk = Configuration::getInstance().memSpec->clk; std::default_random_engine generator; std::bernoulli_distribution distribution((double) SJFprobability / 100.0); diff --git a/DRAMSys/library/src/error/errormodel.cpp b/DRAMSys/library/src/error/errormodel.cpp index eb70a964..861df60a 100644 --- a/DRAMSys/library/src/error/errormodel.cpp +++ b/DRAMSys/library/src/error/errormodel.cpp @@ -46,15 +46,15 @@ void errorModel::init() powerAnalysis = Configuration::getInstance().PowerAnalysis; thermalSim = Configuration::getInstance().ThermalSimulation; // Get Configuration parameters: - burstLenght = Configuration::getInstance().memSpec.BurstLength; - numberOfColumns = Configuration::getInstance().memSpec.NumberOfColumns; + burstLenght = Configuration::getInstance().memSpec->BurstLength; + numberOfColumns = Configuration::getInstance().memSpec->NumberOfColumns; bytesPerColumn = AddressDecoder::getInstance().amount["bytes"]; // Adjust number of bytes per column dynamically to the selected ecc controller bytesPerColumn = Configuration::getInstance().adjustNumBytesAfterECC( bytesPerColumn); - numberOfRows = Configuration::getInstance().memSpec.NumberOfRows; + numberOfRows = Configuration::getInstance().memSpec->NumberOfRows; numberOfBitErrorEvents = 0; @@ -253,7 +253,7 @@ void errorModel::markBitFlips() { double temp = getTemperature(); for (unsigned int row = 0; - row < Configuration::getInstance().memSpec.NumberOfRows; row++) { + row < Configuration::getInstance().memSpec->NumberOfRows; row++) { // If the row has never been accessed ignore it and go to the next one if (lastRowAccess[row] != SC_ZERO_TIME) { // Get the time interval between now and the last acivate/refresh @@ -498,7 +498,7 @@ double errorModel::getTemperature() // TODO // check if this is best way to request information to DRAMPower. unsigned long long clk_cycles = sc_time_stamp().value() / - Configuration::getInstance().memSpec.clk.value(); + Configuration::getInstance().memSpec->clk.value(); DRAMPower->calcWindowEnergy(clk_cycles); float average_power = (float)DRAMPower->getPower().average_power; temperature = TemperatureController::getInstance().getTemperature( diff --git a/DRAMSys/library/src/simulation/Arbiter.cpp b/DRAMSys/library/src/simulation/Arbiter.cpp index 0459445d..b1287f7e 100644 --- a/DRAMSys/library/src/simulation/Arbiter.cpp +++ b/DRAMSys/library/src/simulation/Arbiter.cpp @@ -82,7 +82,7 @@ tlm_sync_enum Arbiter::nb_transport_fw(int id, tlm_generic_payload &payload, } else if (phase == END_RESP) { - notDelay += Configuration::getInstance().memSpec.clk; + notDelay += Configuration::getInstance().memSpec->clk; payload.release(); } diff --git a/DRAMSys/library/src/simulation/Dram.cpp b/DRAMSys/library/src/simulation/Dram.cpp index e18f1456..5dc28899 100644 --- a/DRAMSys/library/src/simulation/Dram.cpp +++ b/DRAMSys/library/src/simulation/Dram.cpp @@ -90,26 +90,26 @@ Dram::Dram(sc_module_name) : tSocket("socket") if (powerAnalysis) { - sc_time clk = Configuration::getInstance().memSpec.clk; + sc_time clk = Configuration::getInstance().memSpec->clk; MemArchitectureSpec memArchSpec; memArchSpec.burstLength = - Configuration::getInstance().memSpec.BurstLength; - memArchSpec.dataRate = Configuration::getInstance().memSpec.DataRate; + Configuration::getInstance().memSpec->BurstLength; + memArchSpec.dataRate = Configuration::getInstance().memSpec->DataRate; memArchSpec.nbrOfRows = - Configuration::getInstance().memSpec.NumberOfRows; + Configuration::getInstance().memSpec->NumberOfRows; memArchSpec.nbrOfBanks = - Configuration::getInstance().memSpec.NumberOfBanks; + Configuration::getInstance().memSpec->NumberOfBanks; memArchSpec.nbrOfColumns = - Configuration::getInstance().memSpec.NumberOfColumns; + Configuration::getInstance().memSpec->NumberOfColumns; memArchSpec.nbrOfRanks = - Configuration::getInstance().memSpec.NumberOfRanks; - memArchSpec.width = Configuration::getInstance().memSpec.bitWidth; + Configuration::getInstance().memSpec->NumberOfRanks; + memArchSpec.width = Configuration::getInstance().memSpec->bitWidth; memArchSpec.nbrOfBankGroups = - Configuration::getInstance().memSpec.NumberOfBankGroups; - memArchSpec.twoVoltageDomains = (Configuration::getInstance().memSpec.vDD2 == 0 + Configuration::getInstance().memSpec->NumberOfBankGroups; + memArchSpec.twoVoltageDomains = (Configuration::getInstance().memSpec->vDD2 == 0 ? false : true); - memArchSpec.dll = Configuration::getInstance().memSpec.DLL; + memArchSpec.dll = Configuration::getInstance().memSpec->DLL; MemTimingSpec memTimingSpec; memTimingSpec.FAWB = Configuration::getInstance().tfawbclk; @@ -119,74 +119,74 @@ Dram::Dram(sc_module_name) : tSocket("socket") memTimingSpec.RRDB = Configuration::getInstance().trrdblclk; memTimingSpec.RRDB_L = Configuration::getInstance().trrdblclk; memTimingSpec.RRDB_S = Configuration::getInstance().trrdblclk; - memTimingSpec.AL = Configuration::getInstance().memSpec.tAL / clk; - memTimingSpec.CCD = Configuration::getInstance().memSpec.tCCD_S / clk; - memTimingSpec.CCD_L = Configuration::getInstance().memSpec.tCCD_L / clk; - memTimingSpec.CCD_S = Configuration::getInstance().memSpec.tCCD_S / clk; - memTimingSpec.CKE = Configuration::getInstance().memSpec.tCKE / clk; - memTimingSpec.CKESR = Configuration::getInstance().memSpec.tCKESR / clk; - memTimingSpec.clkMhz = Configuration::getInstance().memSpec.clkMHz; + memTimingSpec.AL = Configuration::getInstance().memSpec->tAL / clk; + memTimingSpec.CCD = Configuration::getInstance().memSpec->tCCD_S / clk; + memTimingSpec.CCD_L = Configuration::getInstance().memSpec->tCCD_L / clk; + memTimingSpec.CCD_S = Configuration::getInstance().memSpec->tCCD_S / clk; + memTimingSpec.CKE = Configuration::getInstance().memSpec->tCKE / clk; + memTimingSpec.CKESR = Configuration::getInstance().memSpec->tCKESR / clk; + memTimingSpec.clkMhz = Configuration::getInstance().memSpec->clkMHz; // See also MemTimingSpec.cc in DRAMPower - memTimingSpec.clkPeriod = 1000.0 / Configuration::getInstance().memSpec.clkMHz; - memTimingSpec.DQSCK = Configuration::getInstance().memSpec.tDQSCK / clk; - memTimingSpec.FAW = Configuration::getInstance().memSpec.tNAW / clk; - memTimingSpec.RAS = Configuration::getInstance().memSpec.tRAS / clk; - memTimingSpec.RC = Configuration::getInstance().memSpec.tRC / clk; - memTimingSpec.RCD = Configuration::getInstance().memSpec.tRCD / clk; - memTimingSpec.REFI = Configuration::getInstance().memSpec.tREFI / clk; + memTimingSpec.clkPeriod = 1000.0 / Configuration::getInstance().memSpec->clkMHz; + memTimingSpec.DQSCK = Configuration::getInstance().memSpec->tDQSCK / clk; + memTimingSpec.FAW = Configuration::getInstance().memSpec->tNAW / clk; + memTimingSpec.RAS = Configuration::getInstance().memSpec->tRAS / clk; + memTimingSpec.RC = Configuration::getInstance().memSpec->tRC / clk; + memTimingSpec.RCD = Configuration::getInstance().memSpec->tRCD / clk; + memTimingSpec.REFI = Configuration::getInstance().memSpec->tREFI / clk; auto m = Configuration::getInstance().getRefMode(); if (m == 4) - memTimingSpec.RFC = Configuration::getInstance().memSpec.tRFC4 / clk; + memTimingSpec.RFC = Configuration::getInstance().memSpec->tRFC4 / clk; else if (m == 2) - memTimingSpec.RFC = Configuration::getInstance().memSpec.tRFC2 / clk; + memTimingSpec.RFC = Configuration::getInstance().memSpec->tRFC2 / clk; else - memTimingSpec.RFC = Configuration::getInstance().memSpec.tRFC / clk; - memTimingSpec.RL = Configuration::getInstance().memSpec.tRL / clk; - memTimingSpec.RP = Configuration::getInstance().memSpec.tRP / clk; - memTimingSpec.RRD = Configuration::getInstance().memSpec.tRRD_S / clk; - memTimingSpec.RRD_L = Configuration::getInstance().memSpec.tRRD_L / clk; - memTimingSpec.RRD_S = Configuration::getInstance().memSpec.tRRD_S / clk; - memTimingSpec.RTP = Configuration::getInstance().memSpec.tRTP / clk; - memTimingSpec.TAW = Configuration::getInstance().memSpec.tNAW / clk; - memTimingSpec.WL = Configuration::getInstance().memSpec.tWL / clk; - memTimingSpec.WR = Configuration::getInstance().memSpec.tWR / clk; - memTimingSpec.WTR = Configuration::getInstance().memSpec.tWTR_S / clk; - memTimingSpec.WTR_L = Configuration::getInstance().memSpec.tWTR_L / clk; - memTimingSpec.WTR_S = Configuration::getInstance().memSpec.tWTR_S / clk; - memTimingSpec.XP = Configuration::getInstance().memSpec.tXP / clk; - memTimingSpec.XPDLL = Configuration::getInstance().memSpec.tXPDLL / clk; - memTimingSpec.XS = Configuration::getInstance().memSpec.tXSR / clk; - memTimingSpec.XSDLL = Configuration::getInstance().memSpec.tXSRDLL / clk; + memTimingSpec.RFC = Configuration::getInstance().memSpec->tRFC / clk; + memTimingSpec.RL = Configuration::getInstance().memSpec->tRL / clk; + memTimingSpec.RP = Configuration::getInstance().memSpec->tRP / clk; + memTimingSpec.RRD = Configuration::getInstance().memSpec->tRRD_S / clk; + memTimingSpec.RRD_L = Configuration::getInstance().memSpec->tRRD_L / clk; + memTimingSpec.RRD_S = Configuration::getInstance().memSpec->tRRD_S / clk; + memTimingSpec.RTP = Configuration::getInstance().memSpec->tRTP / clk; + memTimingSpec.TAW = Configuration::getInstance().memSpec->tNAW / clk; + memTimingSpec.WL = Configuration::getInstance().memSpec->tWL / clk; + memTimingSpec.WR = Configuration::getInstance().memSpec->tWR / clk; + memTimingSpec.WTR = Configuration::getInstance().memSpec->tWTR_S / clk; + memTimingSpec.WTR_L = Configuration::getInstance().memSpec->tWTR_L / clk; + memTimingSpec.WTR_S = Configuration::getInstance().memSpec->tWTR_S / clk; + memTimingSpec.XP = Configuration::getInstance().memSpec->tXP / clk; + memTimingSpec.XPDLL = Configuration::getInstance().memSpec->tXPDLL / clk; + memTimingSpec.XS = Configuration::getInstance().memSpec->tXSR / clk; + memTimingSpec.XSDLL = Configuration::getInstance().memSpec->tXSRDLL / clk; MemPowerSpec memPowerSpec; - memPowerSpec.idd0 = Configuration::getInstance().memSpec.iDD0; - memPowerSpec.idd02 = Configuration::getInstance().memSpec.iDD02; - memPowerSpec.idd2p0 = Configuration::getInstance().memSpec.iDD2P0; - memPowerSpec.idd2p02 = Configuration::getInstance().memSpec.iDD2P02; - memPowerSpec.idd2p1 = Configuration::getInstance().memSpec.iDD2P1; - memPowerSpec.idd2p12 = Configuration::getInstance().memSpec.iDD2P12; - memPowerSpec.idd2n = Configuration::getInstance().memSpec.iDD2N; - memPowerSpec.idd2n2 = Configuration::getInstance().memSpec.iDD2N2; - memPowerSpec.idd3p0 = Configuration::getInstance().memSpec.iDD3P0; - memPowerSpec.idd3p02 = Configuration::getInstance().memSpec.iDD3P02; - memPowerSpec.idd3p1 = Configuration::getInstance().memSpec.iDD3P1; - memPowerSpec.idd3p12 = Configuration::getInstance().memSpec.iDD3P12; - memPowerSpec.idd3n = Configuration::getInstance().memSpec.iDD3N; - memPowerSpec.idd3n2 = Configuration::getInstance().memSpec.iDD3N2; - memPowerSpec.idd4r = Configuration::getInstance().memSpec.iDD4R; - memPowerSpec.idd4r2 = Configuration::getInstance().memSpec.iDD4R2; - memPowerSpec.idd4w = Configuration::getInstance().memSpec.iDD4W; - memPowerSpec.idd4w2 = Configuration::getInstance().memSpec.iDD4W2; - memPowerSpec.idd5 = Configuration::getInstance().memSpec.iDD5; - memPowerSpec.idd52 = Configuration::getInstance().memSpec.iDD52; - memPowerSpec.idd6 = Configuration::getInstance().memSpec.iDD6; - memPowerSpec.idd62 = Configuration::getInstance().memSpec.iDD62; - memPowerSpec.vdd = Configuration::getInstance().memSpec.vDD; - memPowerSpec.vdd2 = Configuration::getInstance().memSpec.vDD2; + memPowerSpec.idd0 = Configuration::getInstance().memSpec->iDD0; + memPowerSpec.idd02 = Configuration::getInstance().memSpec->iDD02; + memPowerSpec.idd2p0 = Configuration::getInstance().memSpec->iDD2P0; + memPowerSpec.idd2p02 = Configuration::getInstance().memSpec->iDD2P02; + memPowerSpec.idd2p1 = Configuration::getInstance().memSpec->iDD2P1; + memPowerSpec.idd2p12 = Configuration::getInstance().memSpec->iDD2P12; + memPowerSpec.idd2n = Configuration::getInstance().memSpec->iDD2N; + memPowerSpec.idd2n2 = Configuration::getInstance().memSpec->iDD2N2; + memPowerSpec.idd3p0 = Configuration::getInstance().memSpec->iDD3P0; + memPowerSpec.idd3p02 = Configuration::getInstance().memSpec->iDD3P02; + memPowerSpec.idd3p1 = Configuration::getInstance().memSpec->iDD3P1; + memPowerSpec.idd3p12 = Configuration::getInstance().memSpec->iDD3P12; + memPowerSpec.idd3n = Configuration::getInstance().memSpec->iDD3N; + memPowerSpec.idd3n2 = Configuration::getInstance().memSpec->iDD3N2; + memPowerSpec.idd4r = Configuration::getInstance().memSpec->iDD4R; + memPowerSpec.idd4r2 = Configuration::getInstance().memSpec->iDD4R2; + memPowerSpec.idd4w = Configuration::getInstance().memSpec->iDD4W; + memPowerSpec.idd4w2 = Configuration::getInstance().memSpec->iDD4W2; + memPowerSpec.idd5 = Configuration::getInstance().memSpec->iDD5; + memPowerSpec.idd52 = Configuration::getInstance().memSpec->iDD52; + memPowerSpec.idd6 = Configuration::getInstance().memSpec->iDD6; + memPowerSpec.idd62 = Configuration::getInstance().memSpec->iDD62; + memPowerSpec.vdd = Configuration::getInstance().memSpec->vDD; + memPowerSpec.vdd2 = Configuration::getInstance().memSpec->vDD2; MemorySpecification memSpec; - memSpec.id = Configuration::getInstance().memSpec.MemoryId; - memSpec.memoryType = Configuration::getInstance().memSpec.MemoryType; + memSpec.id = Configuration::getInstance().memSpec->MemoryId; + memSpec.memoryType = Configuration::getInstance().memSpec->MemoryType; memSpec.memTimingSpec = memTimingSpec; memSpec.memPowerSpec = memPowerSpec; memSpec.memArchSpec = memArchSpec; @@ -202,7 +202,7 @@ Dram::Dram(sc_module_name) : tSocket("socket") // For each bank in a channel a error Model is created: if (StoreMode == StorageMode::ErrorModel) { - for (unsigned i = 0; i < Configuration::getInstance().memSpec.NumberOfBanks; + for (unsigned i = 0; i < Configuration::getInstance().memSpec->NumberOfBanks; i++) { errorModel *em; @@ -242,9 +242,9 @@ Dram::~Dram() // Bandwidth: sc_time activeTime = numberOfTransactionsServed - * Configuration::getInstance().memSpec.BurstLength - / Configuration::getInstance().memSpec.DataRate - * Configuration::getInstance().memSpec.clk; + * Configuration::getInstance().memSpec->BurstLength + / Configuration::getInstance().memSpec->DataRate + * Configuration::getInstance().memSpec->clk; sc_time idleTime = dramController->getIdleTime(); sc_time endTime = dramController->getEndTime(); @@ -255,11 +255,11 @@ Dram::~Dram() double maxBandwidth = ( // clk in Mhz e.g. 800 [MHz]: - (1000000 / Configuration::getInstance().memSpec.clk.to_double()) + (1000000 / Configuration::getInstance().memSpec->clk.to_double()) // DataRate e.g. 2 - * Configuration::getInstance().memSpec.DataRate + * Configuration::getInstance().memSpec->DataRate // BusWidth e.g. 8 or 64 - * Configuration::getInstance().memSpec.bitWidth + * Configuration::getInstance().memSpec->bitWidth // Number of devices on a DIMM e.g. 8 * Configuration::getInstance().NumberOfDevicesOnDIMM ) / ( 1024 ); @@ -303,7 +303,7 @@ tlm_sync_enum Dram::nb_transport_fw(tlm_generic_payload &payload, if (powerAnalysis) { cycle = sc_time_stamp().value() / - Configuration::getInstance().memSpec.clk.value(); + Configuration::getInstance().memSpec->clk.value(); } if (phase == BEGIN_PREB) diff --git a/DRAMSys/library/src/simulation/RecordableDram.cpp b/DRAMSys/library/src/simulation/RecordableDram.cpp index 7ba789ef..295cac31 100644 --- a/DRAMSys/library/src/simulation/RecordableDram.cpp +++ b/DRAMSys/library/src/simulation/RecordableDram.cpp @@ -105,7 +105,7 @@ void RecordableDram::powerWindow() wait(powerWindowSize); clk_cycles = sc_time_stamp().value() / - Configuration::getInstance().memSpec.clk.value(); + Configuration::getInstance().memSpec->clk.value(); DRAMPower->calcWindowEnergy(clk_cycles); diff --git a/DRAMSys/library/src/simulation/RecordableDram.h b/DRAMSys/library/src/simulation/RecordableDram.h index 191fc868..a362f2cc 100644 --- a/DRAMSys/library/src/simulation/RecordableDram.h +++ b/DRAMSys/library/src/simulation/RecordableDram.h @@ -56,7 +56,7 @@ protected: private: TlmRecorder *tlmRecorder; - sc_time powerWindowSize = Configuration::getInstance().memSpec.clk * + sc_time powerWindowSize = Configuration::getInstance().memSpec->clk * Configuration::getInstance().WindowSize; // When working with floats, we have to decide ourselves what is an diff --git a/DRAMSys/library/src/simulation/StlPlayer.h b/DRAMSys/library/src/simulation/StlPlayer.h index b8e23bbd..cace8884 100644 --- a/DRAMSys/library/src/simulation/StlPlayer.h +++ b/DRAMSys/library/src/simulation/StlPlayer.h @@ -61,7 +61,7 @@ public: SC_REPORT_FATAL(0, (string("Could not open trace ") + pathToTrace).c_str()); this->playerClk = playerClk; - this->burstlength = Configuration::getInstance().memSpec.BurstLength; + this->burstlength = Configuration::getInstance().memSpec->BurstLength; this->dataLength = Configuration::getInstance().getBytesPerBurst(); this->lineCnt = 0; } diff --git a/DRAMSys/library/src/simulation/TraceGenerator.h b/DRAMSys/library/src/simulation/TraceGenerator.h index 7a1ebec4..c6e5cd12 100644 --- a/DRAMSys/library/src/simulation/TraceGenerator.h +++ b/DRAMSys/library/src/simulation/TraceGenerator.h @@ -50,11 +50,11 @@ public: TracePlayerListener *listener) : TracePlayer(listener), transCounter(0) { if (clkMhz == 0) - clk = Configuration::getInstance().memSpec.clk; + clk = Configuration::getInstance().memSpec->clk; else clk = FrequencyToClk(clkMhz); - this->burstlenght = Configuration::getInstance().memSpec.BurstLength; + this->burstlenght = Configuration::getInstance().memSpec->BurstLength; } virtual void nextPayload() override From 388a2623af0ae1e3e7d4b8b1e2211f90351217fc Mon Sep 17 00:00:00 2001 From: "Lukas Steiner (2)" Date: Tue, 18 Jun 2019 10:52:04 +0200 Subject: [PATCH 85/97] Preparation for merge with master. --- DRAMSys/library/resources/configs/simulator/ddr3.xml | 2 +- DRAMSys/library/src/controller/Controller.cpp | 4 +--- DRAMSys/library/src/simulation/Arbiter.cpp | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/DRAMSys/library/resources/configs/simulator/ddr3.xml b/DRAMSys/library/resources/configs/simulator/ddr3.xml index f43e4b8c..1613737f 100644 --- a/DRAMSys/library/resources/configs/simulator/ddr3.xml +++ b/DRAMSys/library/resources/configs/simulator/ddr3.xml @@ -1,6 +1,6 @@ - + diff --git a/DRAMSys/library/src/controller/Controller.cpp b/DRAMSys/library/src/controller/Controller.cpp index 2623616e..d9bf6d89 100644 --- a/DRAMSys/library/src/controller/Controller.cpp +++ b/DRAMSys/library/src/controller/Controller.cpp @@ -332,7 +332,7 @@ void Controller::frontendPEQCallback(tlm_generic_payload &payload, to_string(getTotalNumberOfPayloadsInSystem())); payload.acquire(); payloadEntersSystem(payload); - // TODO: Different queues: Fifo: queue per bank, FifoStrict: queue per channel + if (getTotalNumberOfPayloadsInSystem() > controllerCore->config.MaxNrOfTransactions) { @@ -343,7 +343,6 @@ void Controller::frontendPEQCallback(tlm_generic_payload &payload, { payload.set_response_status(tlm::TLM_OK_RESPONSE); sendToFrontend(payload, END_REQ, SC_ZERO_TIME); - // tSocket->nb_transport_bw(*backpressure, END_REQ, SC_ZERO_TIME) scheduler->storeRequest(&payload); scheduleNextFromScheduler(DramExtension::getExtension(payload).getBank()); @@ -360,7 +359,6 @@ void Controller::frontendPEQCallback(tlm_generic_payload &payload, { printDebugMessage("##Backpressure released"); backpressure->set_response_status(tlm::TLM_OK_RESPONSE); - // tSocket->nb_transport_bw(*backpressure, END_REQ, SC_ZERO_TIME) sendToFrontend(*backpressure, END_REQ, SC_ZERO_TIME); scheduler->storeRequest(backpressure); diff --git a/DRAMSys/library/src/simulation/Arbiter.cpp b/DRAMSys/library/src/simulation/Arbiter.cpp index b1287f7e..c68927f8 100644 --- a/DRAMSys/library/src/simulation/Arbiter.cpp +++ b/DRAMSys/library/src/simulation/Arbiter.cpp @@ -66,7 +66,6 @@ Arbiter::Arbiter(sc_module_name /*name*/) : payloadEventQueue(this, &Arbiter::pe tlm_sync_enum Arbiter::nb_transport_fw(int id, tlm_generic_payload &payload, tlm_phase &phase, sc_time &fwDelay) { - // TODO: clkAlign necessary? sc_time notDelay = clkAlign(sc_time_stamp() + fwDelay) - (sc_time_stamp() + fwDelay); if (phase == BEGIN_REQ) From 8f0e59c85e02a407ffb23caddc2d9244c42abc55 Mon Sep 17 00:00:00 2001 From: "Lukas Steiner (2)" Date: Wed, 19 Jun 2019 11:16:38 +0200 Subject: [PATCH 86/97] Included templates for new DRAMs. --- DRAMSys/library/library.pro | 12 ++++- .../configuration/ConfigurationLoader.cpp | 1 + .../core/configuration/ConfigurationLoader.h | 1 + .../controller/core/configuration/MemSpec.h | 1 + DRAMSys/library/src/simulation/DramDDR3.cpp | 41 ++++++++++++++++ DRAMSys/library/src/simulation/DramDDR3.h | 47 +++++++++++++++++++ DRAMSys/library/src/simulation/DramDDR4.cpp | 6 +++ DRAMSys/library/src/simulation/DramDDR4.h | 12 +++++ .../library/src/simulation/DramRecordable.cpp | 41 ++++++++++++++++ .../library/src/simulation/DramRecordable.h | 46 ++++++++++++++++++ .../src/simulation/DramRecordablePower.cpp | 41 ++++++++++++++++ .../src/simulation/DramRecordablePower.h | 46 ++++++++++++++++++ .../library/src/simulation/RecordableDram.cpp | 8 ++-- .../library/src/simulation/RecordableDram.h | 2 +- 14 files changed, 298 insertions(+), 7 deletions(-) create mode 100644 DRAMSys/library/src/simulation/DramDDR3.cpp create mode 100644 DRAMSys/library/src/simulation/DramDDR3.h create mode 100644 DRAMSys/library/src/simulation/DramDDR4.cpp create mode 100644 DRAMSys/library/src/simulation/DramDDR4.h create mode 100644 DRAMSys/library/src/simulation/DramRecordable.cpp create mode 100644 DRAMSys/library/src/simulation/DramRecordable.h create mode 100644 DRAMSys/library/src/simulation/DramRecordablePower.cpp create mode 100644 DRAMSys/library/src/simulation/DramRecordablePower.h diff --git a/DRAMSys/library/library.pro b/DRAMSys/library/library.pro index ab7ca602..6fbf6467 100644 --- a/DRAMSys/library/library.pro +++ b/DRAMSys/library/library.pro @@ -143,7 +143,11 @@ SOURCES += \ src/common/XmlAddressDecoder.cpp \ src/controller/core/timingCalculations.cpp \ src/common/dramExtensions.cpp \ - src/common/utils.cpp + src/common/utils.cpp \ + src/simulation/DramDDR3.cpp \ + src/simulation/DramDDR4.cpp \ + src/simulation/DramRecordable.cpp \ + src/simulation/DramRecordablePower.cpp HEADERS += \ src/common/third_party/tinyxml2/tinyxml2.h \ @@ -220,7 +224,11 @@ HEADERS += \ src/controller/core/timingCalculations.h \ src/common/dramExtensions.h \ src/common/utils.h \ - src/controller/core/configuration/TemperatureSimConfig.h + src/controller/core/configuration/TemperatureSimConfig.h \ + src/simulation/DramDDR3.h \ + src/simulation/DramDDR4.h \ + src/simulation/DramRecordable.h \ + src/simulation/DramRecordablePower.h #src/common/third_party/json/include/nlohmann/json.hpp \ thermalsim = $$(THERMALSIM) diff --git a/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.cpp b/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.cpp index 79b9965f..def1d129 100644 --- a/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.cpp +++ b/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.cpp @@ -32,6 +32,7 @@ * Authors: * Janik Schlemminger * Matthias Jung + * Lukas Steiner */ #include "ConfigurationLoader.h" diff --git a/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.h b/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.h index d7a12c57..7a4e0410 100644 --- a/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.h +++ b/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.h @@ -32,6 +32,7 @@ * Authors: * Janik Schlemminger * Matthias Jung + * Lukas Steiner */ #ifndef CONFIGURATIONLOADER_H diff --git a/DRAMSys/library/src/controller/core/configuration/MemSpec.h b/DRAMSys/library/src/controller/core/configuration/MemSpec.h index fc4fb576..d13f2701 100644 --- a/DRAMSys/library/src/controller/core/configuration/MemSpec.h +++ b/DRAMSys/library/src/controller/core/configuration/MemSpec.h @@ -32,6 +32,7 @@ * Authors: * Janik Schlemminger * Matthias Jung + * Lukas Steiner */ #ifndef MEMSPEC_H diff --git a/DRAMSys/library/src/simulation/DramDDR3.cpp b/DRAMSys/library/src/simulation/DramDDR3.cpp new file mode 100644 index 00000000..1999d3a5 --- /dev/null +++ b/DRAMSys/library/src/simulation/DramDDR3.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019, University of Kaiserslautern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: + * Lukas Steiner + */ + +#include "DramDDR3.h" + +DramDDR3::DramDDR3(sc_module_name name) : Dram(name) +{ + +} diff --git a/DRAMSys/library/src/simulation/DramDDR3.h b/DRAMSys/library/src/simulation/DramDDR3.h new file mode 100644 index 00000000..a64cdeaf --- /dev/null +++ b/DRAMSys/library/src/simulation/DramDDR3.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2019, University of Kaiserslautern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: + * Lukas Steiner + */ + +#ifndef DRAMDDR3_H +#define DRAMDDR3_H + +#include "Dram.h" + +class DramDDR3 : public Dram +{ +public: + DramDDR3(sc_module_name); +}; + +#endif // DRAMDDR3_H diff --git a/DRAMSys/library/src/simulation/DramDDR4.cpp b/DRAMSys/library/src/simulation/DramDDR4.cpp new file mode 100644 index 00000000..1390f29d --- /dev/null +++ b/DRAMSys/library/src/simulation/DramDDR4.cpp @@ -0,0 +1,6 @@ +#include "DramDDR4.h" + +DramDDR4::DramDDR4(sc_module_name name) : Dram(name) +{ + +} diff --git a/DRAMSys/library/src/simulation/DramDDR4.h b/DRAMSys/library/src/simulation/DramDDR4.h new file mode 100644 index 00000000..14212125 --- /dev/null +++ b/DRAMSys/library/src/simulation/DramDDR4.h @@ -0,0 +1,12 @@ +#ifndef DRAMDDR4_H +#define DRAMDDR4_H + +#include "Dram.h" + +class DramDDR4 : public Dram +{ +public: + DramDDR4(sc_module_name); +}; + +#endif // DRAMDDR4_H diff --git a/DRAMSys/library/src/simulation/DramRecordable.cpp b/DRAMSys/library/src/simulation/DramRecordable.cpp new file mode 100644 index 00000000..85d9d73a --- /dev/null +++ b/DRAMSys/library/src/simulation/DramRecordable.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019, University of Kaiserslautern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: + * Lukas Steiner + */ + +#include "DramRecordable.h" + +DramRecordable::DramRecordable() +{ + +} diff --git a/DRAMSys/library/src/simulation/DramRecordable.h b/DRAMSys/library/src/simulation/DramRecordable.h new file mode 100644 index 00000000..cbbfea32 --- /dev/null +++ b/DRAMSys/library/src/simulation/DramRecordable.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019, University of Kaiserslautern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: + * Lukas Steiner + */ + +#ifndef DRAMRECORDABLE_H +#define DRAMRECORDABLE_H + + +class DramRecordable +{ +public: + DramRecordable(); +}; + +#endif // DRAMRECORDABLE_H diff --git a/DRAMSys/library/src/simulation/DramRecordablePower.cpp b/DRAMSys/library/src/simulation/DramRecordablePower.cpp new file mode 100644 index 00000000..c1287cd3 --- /dev/null +++ b/DRAMSys/library/src/simulation/DramRecordablePower.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019, University of Kaiserslautern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: + * Lukas Steiner + */ + +#include "DramRecordablePower.h" + +DramRecordablePower::DramRecordablePower() +{ + +} diff --git a/DRAMSys/library/src/simulation/DramRecordablePower.h b/DRAMSys/library/src/simulation/DramRecordablePower.h new file mode 100644 index 00000000..032022bd --- /dev/null +++ b/DRAMSys/library/src/simulation/DramRecordablePower.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019, University of Kaiserslautern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: + * Lukas Steiner + */ + +#ifndef DRAMRECORDABLEPOWER_H +#define DRAMRECORDABLEPOWER_H + + +class DramRecordablePower +{ +public: + DramRecordablePower(); +}; + +#endif // DRAMRECORDABLEPOWER_H diff --git a/DRAMSys/library/src/simulation/RecordableDram.cpp b/DRAMSys/library/src/simulation/RecordableDram.cpp index 295cac31..699f0a74 100644 --- a/DRAMSys/library/src/simulation/RecordableDram.cpp +++ b/DRAMSys/library/src/simulation/RecordableDram.cpp @@ -98,19 +98,19 @@ tlm_sync_enum RecordableDram::nb_transport_fw(tlm_generic_payload &payload, // It estimates the current average power which will be stored in the trace database for visualization purposes. void RecordableDram::powerWindow() { - unsigned long long clk_cycles = 0; + unsigned long long clkCycles = 0; do { // At the very beginning (zero clock cycles) the energy is 0, so we wait first wait(powerWindowSize); - clk_cycles = sc_time_stamp().value() / + clkCycles = sc_time_stamp().value() / Configuration::getInstance().memSpec->clk.value(); - DRAMPower->calcWindowEnergy(clk_cycles); + DRAMPower->calcWindowEnergy(clkCycles); // During operation the energy should never be zero since the device is always consuming - assert(!is_equal(DRAMPower->getEnergy().window_energy, 0.0)); + assert(!isEqual(DRAMPower->getEnergy().window_energy, 0.0)); // Store the time (in seconds) and the current average power (in mW) into the database recordPower(); diff --git a/DRAMSys/library/src/simulation/RecordableDram.h b/DRAMSys/library/src/simulation/RecordableDram.h index a362f2cc..0434177a 100644 --- a/DRAMSys/library/src/simulation/RecordableDram.h +++ b/DRAMSys/library/src/simulation/RecordableDram.h @@ -62,7 +62,7 @@ private: // When working with floats, we have to decide ourselves what is an // acceptable definition for "equal". Here the number is compared with a // suitable error margin (0.00001). - bool is_equal(double a, double b, const double epsilon = 1e-05) + bool isEqual(double a, double b, const double epsilon = 1e-05) { return std::fabs(a - b) < epsilon; } From d69cb555ac5ba564439d93ad63907f0a51485b74 Mon Sep 17 00:00:00 2001 From: "Lukas Steiner (2)" Date: Wed, 19 Jun 2019 13:59:01 +0200 Subject: [PATCH 87/97] Templating for DRAMs is working. --- DRAMSys/library/src/simulation/DRAMSys.cpp | 9 ++++- DRAMSys/library/src/simulation/DramDDR3.cpp | 1 + DRAMSys/library/src/simulation/DramDDR3.h | 1 + DRAMSys/library/src/simulation/DramDDR4.cpp | 36 +++++++++++++++++++ DRAMSys/library/src/simulation/DramDDR4.h | 1 + .../library/src/simulation/DramRecordable.cpp | 8 ++++- .../library/src/simulation/DramRecordable.h | 10 ++++-- .../src/simulation/DramRecordablePower.cpp | 8 ++++- .../src/simulation/DramRecordablePower.h | 8 +++-- 9 files changed, 75 insertions(+), 7 deletions(-) diff --git a/DRAMSys/library/src/simulation/DRAMSys.cpp b/DRAMSys/library/src/simulation/DRAMSys.cpp index ee5b7c51..563c2a41 100644 --- a/DRAMSys/library/src/simulation/DRAMSys.cpp +++ b/DRAMSys/library/src/simulation/DRAMSys.cpp @@ -54,6 +54,10 @@ #include "../simulation/TemperatureController.h" #include "../controller/Controller.h" #include "../error/ecchamming.h" +#include "DramRecordable.h" +#include "DramRecordablePower.h" +#include "DramDDR3.h" +#include "RecordableDram.h" using namespace std; @@ -240,6 +244,8 @@ void DRAMSys::instantiateModules(const string &traceName, // Create arbiter arbiter = new Arbiter("arbiter"); + std::string testString = "test"; + //DramRecordable testDram(testString.c_str(), tlmRecorders[0]); // Create DRAM for (size_t i = 0; @@ -257,7 +263,8 @@ void DRAMSys::instantiateModules(const string &traceName, str = "dram" + std::to_string(i); Dram *dram; if (recordingEnabled) - dram = new RecordableDram(str.c_str(), tlmRecorders[i]); + //dram = new RecordableDram(str.c_str(), tlmRecorders[i]); + dram = new DramRecordablePower(str.c_str(), tlmRecorders[i]); else dram = new Dram(str.c_str()); drams.push_back(dram); diff --git a/DRAMSys/library/src/simulation/DramDDR3.cpp b/DRAMSys/library/src/simulation/DramDDR3.cpp index 1999d3a5..416f7c63 100644 --- a/DRAMSys/library/src/simulation/DramDDR3.cpp +++ b/DRAMSys/library/src/simulation/DramDDR3.cpp @@ -34,6 +34,7 @@ */ #include "DramDDR3.h" +#include "Dram.h" DramDDR3::DramDDR3(sc_module_name name) : Dram(name) { diff --git a/DRAMSys/library/src/simulation/DramDDR3.h b/DRAMSys/library/src/simulation/DramDDR3.h index a64cdeaf..c1aa87ca 100644 --- a/DRAMSys/library/src/simulation/DramDDR3.h +++ b/DRAMSys/library/src/simulation/DramDDR3.h @@ -42,6 +42,7 @@ class DramDDR3 : public Dram { public: DramDDR3(sc_module_name); + SC_HAS_PROCESS(DramDDR3); }; #endif // DRAMDDR3_H diff --git a/DRAMSys/library/src/simulation/DramDDR4.cpp b/DRAMSys/library/src/simulation/DramDDR4.cpp index 1390f29d..4eb6bb39 100644 --- a/DRAMSys/library/src/simulation/DramDDR4.cpp +++ b/DRAMSys/library/src/simulation/DramDDR4.cpp @@ -1,4 +1,40 @@ +/* + * Copyright (c) 2019, University of Kaiserslautern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: + * Lukas Steiner + */ + #include "DramDDR4.h" +#include "Dram.h" DramDDR4::DramDDR4(sc_module_name name) : Dram(name) { diff --git a/DRAMSys/library/src/simulation/DramDDR4.h b/DRAMSys/library/src/simulation/DramDDR4.h index 14212125..855a3aaf 100644 --- a/DRAMSys/library/src/simulation/DramDDR4.h +++ b/DRAMSys/library/src/simulation/DramDDR4.h @@ -7,6 +7,7 @@ class DramDDR4 : public Dram { public: DramDDR4(sc_module_name); + SC_HAS_PROCESS(DramDDR4); }; #endif // DRAMDDR4_H diff --git a/DRAMSys/library/src/simulation/DramRecordable.cpp b/DRAMSys/library/src/simulation/DramRecordable.cpp index 85d9d73a..9b1fec3c 100644 --- a/DRAMSys/library/src/simulation/DramRecordable.cpp +++ b/DRAMSys/library/src/simulation/DramRecordable.cpp @@ -34,8 +34,14 @@ */ #include "DramRecordable.h" +#include "RecordableDram.h" -DramRecordable::DramRecordable() +template +DramRecordable::DramRecordable(sc_module_name name, TlmRecorder *tlmRecorder) + : BaseDram(name, tlmRecorder) { } + +template class DramRecordable; + diff --git a/DRAMSys/library/src/simulation/DramRecordable.h b/DRAMSys/library/src/simulation/DramRecordable.h index cbbfea32..95139b1f 100644 --- a/DRAMSys/library/src/simulation/DramRecordable.h +++ b/DRAMSys/library/src/simulation/DramRecordable.h @@ -36,11 +36,17 @@ #ifndef DRAMRECORDABLE_H #define DRAMRECORDABLE_H +#include "DramDDR3.h" +#include "DramDDR4.h" +#include "RecordableDram.h" +#include "../common/TlmRecorder.h" -class DramRecordable +template +class DramRecordable : public BaseDram { public: - DramRecordable(); + DramRecordable(sc_module_name name, TlmRecorder *tlmRecorder); + SC_HAS_PROCESS(DramRecordable); }; #endif // DRAMRECORDABLE_H diff --git a/DRAMSys/library/src/simulation/DramRecordablePower.cpp b/DRAMSys/library/src/simulation/DramRecordablePower.cpp index c1287cd3..bc855e77 100644 --- a/DRAMSys/library/src/simulation/DramRecordablePower.cpp +++ b/DRAMSys/library/src/simulation/DramRecordablePower.cpp @@ -34,8 +34,14 @@ */ #include "DramRecordablePower.h" +#include "RecordableDram.h" -DramRecordablePower::DramRecordablePower() +template +DramRecordablePower::DramRecordablePower + (sc_module_name name, TlmRecorder *tlmRecorder) + : DramRecordable(name, tlmRecorder) { } + +template class DramRecordablePower; diff --git a/DRAMSys/library/src/simulation/DramRecordablePower.h b/DRAMSys/library/src/simulation/DramRecordablePower.h index 032022bd..b38dacb2 100644 --- a/DRAMSys/library/src/simulation/DramRecordablePower.h +++ b/DRAMSys/library/src/simulation/DramRecordablePower.h @@ -36,11 +36,15 @@ #ifndef DRAMRECORDABLEPOWER_H #define DRAMRECORDABLEPOWER_H +#include "DramRecordable.h" +#include "../common/TlmRecorder.h" -class DramRecordablePower +template +class DramRecordablePower : public DramRecordable { public: - DramRecordablePower(); + DramRecordablePower(sc_module_name name, TlmRecorder *tlmRecorder); + SC_HAS_PROCESS(DramRecordablePower); }; #endif // DRAMRECORDABLEPOWER_H From 27fed220035e89af0a039e1e0036f9369b6df0c1 Mon Sep 17 00:00:00 2001 From: Lukas Steiner Date: Sat, 22 Jun 2019 20:49:57 +0200 Subject: [PATCH 88/97] Revert "Templating for DRAMs is working." This reverts commit d69cb555ac5ba564439d93ad63907f0a51485b74. --- DRAMSys/library/src/simulation/DRAMSys.cpp | 9 +---- DRAMSys/library/src/simulation/DramDDR3.cpp | 1 - DRAMSys/library/src/simulation/DramDDR3.h | 1 - DRAMSys/library/src/simulation/DramDDR4.cpp | 36 ------------------- DRAMSys/library/src/simulation/DramDDR4.h | 1 - .../library/src/simulation/DramRecordable.cpp | 8 +---- .../library/src/simulation/DramRecordable.h | 10 ++---- .../src/simulation/DramRecordablePower.cpp | 8 +---- .../src/simulation/DramRecordablePower.h | 8 ++--- 9 files changed, 7 insertions(+), 75 deletions(-) diff --git a/DRAMSys/library/src/simulation/DRAMSys.cpp b/DRAMSys/library/src/simulation/DRAMSys.cpp index 563c2a41..ee5b7c51 100644 --- a/DRAMSys/library/src/simulation/DRAMSys.cpp +++ b/DRAMSys/library/src/simulation/DRAMSys.cpp @@ -54,10 +54,6 @@ #include "../simulation/TemperatureController.h" #include "../controller/Controller.h" #include "../error/ecchamming.h" -#include "DramRecordable.h" -#include "DramRecordablePower.h" -#include "DramDDR3.h" -#include "RecordableDram.h" using namespace std; @@ -244,8 +240,6 @@ void DRAMSys::instantiateModules(const string &traceName, // Create arbiter arbiter = new Arbiter("arbiter"); - std::string testString = "test"; - //DramRecordable testDram(testString.c_str(), tlmRecorders[0]); // Create DRAM for (size_t i = 0; @@ -263,8 +257,7 @@ void DRAMSys::instantiateModules(const string &traceName, str = "dram" + std::to_string(i); Dram *dram; if (recordingEnabled) - //dram = new RecordableDram(str.c_str(), tlmRecorders[i]); - dram = new DramRecordablePower(str.c_str(), tlmRecorders[i]); + dram = new RecordableDram(str.c_str(), tlmRecorders[i]); else dram = new Dram(str.c_str()); drams.push_back(dram); diff --git a/DRAMSys/library/src/simulation/DramDDR3.cpp b/DRAMSys/library/src/simulation/DramDDR3.cpp index 416f7c63..1999d3a5 100644 --- a/DRAMSys/library/src/simulation/DramDDR3.cpp +++ b/DRAMSys/library/src/simulation/DramDDR3.cpp @@ -34,7 +34,6 @@ */ #include "DramDDR3.h" -#include "Dram.h" DramDDR3::DramDDR3(sc_module_name name) : Dram(name) { diff --git a/DRAMSys/library/src/simulation/DramDDR3.h b/DRAMSys/library/src/simulation/DramDDR3.h index c1aa87ca..a64cdeaf 100644 --- a/DRAMSys/library/src/simulation/DramDDR3.h +++ b/DRAMSys/library/src/simulation/DramDDR3.h @@ -42,7 +42,6 @@ class DramDDR3 : public Dram { public: DramDDR3(sc_module_name); - SC_HAS_PROCESS(DramDDR3); }; #endif // DRAMDDR3_H diff --git a/DRAMSys/library/src/simulation/DramDDR4.cpp b/DRAMSys/library/src/simulation/DramDDR4.cpp index 4eb6bb39..1390f29d 100644 --- a/DRAMSys/library/src/simulation/DramDDR4.cpp +++ b/DRAMSys/library/src/simulation/DramDDR4.cpp @@ -1,40 +1,4 @@ -/* - * Copyright (c) 2019, University of Kaiserslautern - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: - * Lukas Steiner - */ - #include "DramDDR4.h" -#include "Dram.h" DramDDR4::DramDDR4(sc_module_name name) : Dram(name) { diff --git a/DRAMSys/library/src/simulation/DramDDR4.h b/DRAMSys/library/src/simulation/DramDDR4.h index 855a3aaf..14212125 100644 --- a/DRAMSys/library/src/simulation/DramDDR4.h +++ b/DRAMSys/library/src/simulation/DramDDR4.h @@ -7,7 +7,6 @@ class DramDDR4 : public Dram { public: DramDDR4(sc_module_name); - SC_HAS_PROCESS(DramDDR4); }; #endif // DRAMDDR4_H diff --git a/DRAMSys/library/src/simulation/DramRecordable.cpp b/DRAMSys/library/src/simulation/DramRecordable.cpp index 9b1fec3c..85d9d73a 100644 --- a/DRAMSys/library/src/simulation/DramRecordable.cpp +++ b/DRAMSys/library/src/simulation/DramRecordable.cpp @@ -34,14 +34,8 @@ */ #include "DramRecordable.h" -#include "RecordableDram.h" -template -DramRecordable::DramRecordable(sc_module_name name, TlmRecorder *tlmRecorder) - : BaseDram(name, tlmRecorder) +DramRecordable::DramRecordable() { } - -template class DramRecordable; - diff --git a/DRAMSys/library/src/simulation/DramRecordable.h b/DRAMSys/library/src/simulation/DramRecordable.h index 95139b1f..cbbfea32 100644 --- a/DRAMSys/library/src/simulation/DramRecordable.h +++ b/DRAMSys/library/src/simulation/DramRecordable.h @@ -36,17 +36,11 @@ #ifndef DRAMRECORDABLE_H #define DRAMRECORDABLE_H -#include "DramDDR3.h" -#include "DramDDR4.h" -#include "RecordableDram.h" -#include "../common/TlmRecorder.h" -template -class DramRecordable : public BaseDram +class DramRecordable { public: - DramRecordable(sc_module_name name, TlmRecorder *tlmRecorder); - SC_HAS_PROCESS(DramRecordable); + DramRecordable(); }; #endif // DRAMRECORDABLE_H diff --git a/DRAMSys/library/src/simulation/DramRecordablePower.cpp b/DRAMSys/library/src/simulation/DramRecordablePower.cpp index bc855e77..c1287cd3 100644 --- a/DRAMSys/library/src/simulation/DramRecordablePower.cpp +++ b/DRAMSys/library/src/simulation/DramRecordablePower.cpp @@ -34,14 +34,8 @@ */ #include "DramRecordablePower.h" -#include "RecordableDram.h" -template -DramRecordablePower::DramRecordablePower - (sc_module_name name, TlmRecorder *tlmRecorder) - : DramRecordable(name, tlmRecorder) +DramRecordablePower::DramRecordablePower() { } - -template class DramRecordablePower; diff --git a/DRAMSys/library/src/simulation/DramRecordablePower.h b/DRAMSys/library/src/simulation/DramRecordablePower.h index b38dacb2..032022bd 100644 --- a/DRAMSys/library/src/simulation/DramRecordablePower.h +++ b/DRAMSys/library/src/simulation/DramRecordablePower.h @@ -36,15 +36,11 @@ #ifndef DRAMRECORDABLEPOWER_H #define DRAMRECORDABLEPOWER_H -#include "DramRecordable.h" -#include "../common/TlmRecorder.h" -template -class DramRecordablePower : public DramRecordable +class DramRecordablePower { public: - DramRecordablePower(sc_module_name name, TlmRecorder *tlmRecorder); - SC_HAS_PROCESS(DramRecordablePower); + DramRecordablePower(); }; #endif // DRAMRECORDABLEPOWER_H From 882a0eaa90e78529e44eec9c86f2363b8bddc1b1 Mon Sep 17 00:00:00 2001 From: Lukas Steiner Date: Sat, 22 Jun 2019 20:50:07 +0200 Subject: [PATCH 89/97] Revert "Included templates for new DRAMs." This reverts commit 8f0e59c85e02a407ffb23caddc2d9244c42abc55. --- DRAMSys/library/library.pro | 12 +---- .../configuration/ConfigurationLoader.cpp | 1 - .../core/configuration/ConfigurationLoader.h | 1 - .../controller/core/configuration/MemSpec.h | 1 - DRAMSys/library/src/simulation/DramDDR3.cpp | 41 ---------------- DRAMSys/library/src/simulation/DramDDR3.h | 47 ------------------- DRAMSys/library/src/simulation/DramDDR4.cpp | 6 --- DRAMSys/library/src/simulation/DramDDR4.h | 12 ----- .../library/src/simulation/DramRecordable.cpp | 41 ---------------- .../library/src/simulation/DramRecordable.h | 46 ------------------ .../src/simulation/DramRecordablePower.cpp | 41 ---------------- .../src/simulation/DramRecordablePower.h | 46 ------------------ .../library/src/simulation/RecordableDram.cpp | 8 ++-- .../library/src/simulation/RecordableDram.h | 2 +- 14 files changed, 7 insertions(+), 298 deletions(-) delete mode 100644 DRAMSys/library/src/simulation/DramDDR3.cpp delete mode 100644 DRAMSys/library/src/simulation/DramDDR3.h delete mode 100644 DRAMSys/library/src/simulation/DramDDR4.cpp delete mode 100644 DRAMSys/library/src/simulation/DramDDR4.h delete mode 100644 DRAMSys/library/src/simulation/DramRecordable.cpp delete mode 100644 DRAMSys/library/src/simulation/DramRecordable.h delete mode 100644 DRAMSys/library/src/simulation/DramRecordablePower.cpp delete mode 100644 DRAMSys/library/src/simulation/DramRecordablePower.h diff --git a/DRAMSys/library/library.pro b/DRAMSys/library/library.pro index 6fbf6467..ab7ca602 100644 --- a/DRAMSys/library/library.pro +++ b/DRAMSys/library/library.pro @@ -143,11 +143,7 @@ SOURCES += \ src/common/XmlAddressDecoder.cpp \ src/controller/core/timingCalculations.cpp \ src/common/dramExtensions.cpp \ - src/common/utils.cpp \ - src/simulation/DramDDR3.cpp \ - src/simulation/DramDDR4.cpp \ - src/simulation/DramRecordable.cpp \ - src/simulation/DramRecordablePower.cpp + src/common/utils.cpp HEADERS += \ src/common/third_party/tinyxml2/tinyxml2.h \ @@ -224,11 +220,7 @@ HEADERS += \ src/controller/core/timingCalculations.h \ src/common/dramExtensions.h \ src/common/utils.h \ - src/controller/core/configuration/TemperatureSimConfig.h \ - src/simulation/DramDDR3.h \ - src/simulation/DramDDR4.h \ - src/simulation/DramRecordable.h \ - src/simulation/DramRecordablePower.h + src/controller/core/configuration/TemperatureSimConfig.h #src/common/third_party/json/include/nlohmann/json.hpp \ thermalsim = $$(THERMALSIM) diff --git a/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.cpp b/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.cpp index def1d129..79b9965f 100644 --- a/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.cpp +++ b/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.cpp @@ -32,7 +32,6 @@ * Authors: * Janik Schlemminger * Matthias Jung - * Lukas Steiner */ #include "ConfigurationLoader.h" diff --git a/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.h b/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.h index 7a4e0410..d7a12c57 100644 --- a/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.h +++ b/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.h @@ -32,7 +32,6 @@ * Authors: * Janik Schlemminger * Matthias Jung - * Lukas Steiner */ #ifndef CONFIGURATIONLOADER_H diff --git a/DRAMSys/library/src/controller/core/configuration/MemSpec.h b/DRAMSys/library/src/controller/core/configuration/MemSpec.h index d13f2701..fc4fb576 100644 --- a/DRAMSys/library/src/controller/core/configuration/MemSpec.h +++ b/DRAMSys/library/src/controller/core/configuration/MemSpec.h @@ -32,7 +32,6 @@ * Authors: * Janik Schlemminger * Matthias Jung - * Lukas Steiner */ #ifndef MEMSPEC_H diff --git a/DRAMSys/library/src/simulation/DramDDR3.cpp b/DRAMSys/library/src/simulation/DramDDR3.cpp deleted file mode 100644 index 1999d3a5..00000000 --- a/DRAMSys/library/src/simulation/DramDDR3.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2019, University of Kaiserslautern - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: - * Lukas Steiner - */ - -#include "DramDDR3.h" - -DramDDR3::DramDDR3(sc_module_name name) : Dram(name) -{ - -} diff --git a/DRAMSys/library/src/simulation/DramDDR3.h b/DRAMSys/library/src/simulation/DramDDR3.h deleted file mode 100644 index a64cdeaf..00000000 --- a/DRAMSys/library/src/simulation/DramDDR3.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2019, University of Kaiserslautern - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: - * Lukas Steiner - */ - -#ifndef DRAMDDR3_H -#define DRAMDDR3_H - -#include "Dram.h" - -class DramDDR3 : public Dram -{ -public: - DramDDR3(sc_module_name); -}; - -#endif // DRAMDDR3_H diff --git a/DRAMSys/library/src/simulation/DramDDR4.cpp b/DRAMSys/library/src/simulation/DramDDR4.cpp deleted file mode 100644 index 1390f29d..00000000 --- a/DRAMSys/library/src/simulation/DramDDR4.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "DramDDR4.h" - -DramDDR4::DramDDR4(sc_module_name name) : Dram(name) -{ - -} diff --git a/DRAMSys/library/src/simulation/DramDDR4.h b/DRAMSys/library/src/simulation/DramDDR4.h deleted file mode 100644 index 14212125..00000000 --- a/DRAMSys/library/src/simulation/DramDDR4.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef DRAMDDR4_H -#define DRAMDDR4_H - -#include "Dram.h" - -class DramDDR4 : public Dram -{ -public: - DramDDR4(sc_module_name); -}; - -#endif // DRAMDDR4_H diff --git a/DRAMSys/library/src/simulation/DramRecordable.cpp b/DRAMSys/library/src/simulation/DramRecordable.cpp deleted file mode 100644 index 85d9d73a..00000000 --- a/DRAMSys/library/src/simulation/DramRecordable.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2019, University of Kaiserslautern - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: - * Lukas Steiner - */ - -#include "DramRecordable.h" - -DramRecordable::DramRecordable() -{ - -} diff --git a/DRAMSys/library/src/simulation/DramRecordable.h b/DRAMSys/library/src/simulation/DramRecordable.h deleted file mode 100644 index cbbfea32..00000000 --- a/DRAMSys/library/src/simulation/DramRecordable.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2019, University of Kaiserslautern - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: - * Lukas Steiner - */ - -#ifndef DRAMRECORDABLE_H -#define DRAMRECORDABLE_H - - -class DramRecordable -{ -public: - DramRecordable(); -}; - -#endif // DRAMRECORDABLE_H diff --git a/DRAMSys/library/src/simulation/DramRecordablePower.cpp b/DRAMSys/library/src/simulation/DramRecordablePower.cpp deleted file mode 100644 index c1287cd3..00000000 --- a/DRAMSys/library/src/simulation/DramRecordablePower.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2019, University of Kaiserslautern - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: - * Lukas Steiner - */ - -#include "DramRecordablePower.h" - -DramRecordablePower::DramRecordablePower() -{ - -} diff --git a/DRAMSys/library/src/simulation/DramRecordablePower.h b/DRAMSys/library/src/simulation/DramRecordablePower.h deleted file mode 100644 index 032022bd..00000000 --- a/DRAMSys/library/src/simulation/DramRecordablePower.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2019, University of Kaiserslautern - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: - * Lukas Steiner - */ - -#ifndef DRAMRECORDABLEPOWER_H -#define DRAMRECORDABLEPOWER_H - - -class DramRecordablePower -{ -public: - DramRecordablePower(); -}; - -#endif // DRAMRECORDABLEPOWER_H diff --git a/DRAMSys/library/src/simulation/RecordableDram.cpp b/DRAMSys/library/src/simulation/RecordableDram.cpp index 699f0a74..295cac31 100644 --- a/DRAMSys/library/src/simulation/RecordableDram.cpp +++ b/DRAMSys/library/src/simulation/RecordableDram.cpp @@ -98,19 +98,19 @@ tlm_sync_enum RecordableDram::nb_transport_fw(tlm_generic_payload &payload, // It estimates the current average power which will be stored in the trace database for visualization purposes. void RecordableDram::powerWindow() { - unsigned long long clkCycles = 0; + unsigned long long clk_cycles = 0; do { // At the very beginning (zero clock cycles) the energy is 0, so we wait first wait(powerWindowSize); - clkCycles = sc_time_stamp().value() / + clk_cycles = sc_time_stamp().value() / Configuration::getInstance().memSpec->clk.value(); - DRAMPower->calcWindowEnergy(clkCycles); + DRAMPower->calcWindowEnergy(clk_cycles); // During operation the energy should never be zero since the device is always consuming - assert(!isEqual(DRAMPower->getEnergy().window_energy, 0.0)); + assert(!is_equal(DRAMPower->getEnergy().window_energy, 0.0)); // Store the time (in seconds) and the current average power (in mW) into the database recordPower(); diff --git a/DRAMSys/library/src/simulation/RecordableDram.h b/DRAMSys/library/src/simulation/RecordableDram.h index 0434177a..a362f2cc 100644 --- a/DRAMSys/library/src/simulation/RecordableDram.h +++ b/DRAMSys/library/src/simulation/RecordableDram.h @@ -62,7 +62,7 @@ private: // When working with floats, we have to decide ourselves what is an // acceptable definition for "equal". Here the number is compared with a // suitable error margin (0.00001). - bool isEqual(double a, double b, const double epsilon = 1e-05) + bool is_equal(double a, double b, const double epsilon = 1e-05) { return std::fabs(a - b) < epsilon; } From c3da6912a95db4f2c548263988fbf88de279e0c4 Mon Sep 17 00:00:00 2001 From: Lukas Steiner Date: Sat, 22 Jun 2019 21:49:18 +0200 Subject: [PATCH 90/97] Further renaming of schedulers. --- .../library/resources/configs/mcconfigs/fifo.xml | 2 +- .../resources/configs/mcconfigs/fifoStrict.xml | 2 +- .../resources/configs/mcconfigs/fifo_ecc.xml | 2 +- .../resources/configs/mcconfigs/fr_fcfs.xml | 2 +- .../resources/configs/mcconfigs/fr_fcfs_grp.xml | 2 +- .../resources/configs/mcconfigs/fr_fcfs_rp.xml | 2 +- .../library/resources/configs/mcconfigs/grp.xml | 2 +- .../resources/configs/mcconfigs/rgrmccfg.xml | 2 +- DRAMSys/library/src/controller/Controller.cpp | 12 ++++++------ .../library/src/controller/scheduler/FrFcfs.cpp | 4 ++-- DRAMSys/traceAnalyzer/scripts/tests.py | 4 ++-- README.md | 14 +++++++++----- 12 files changed, 27 insertions(+), 23 deletions(-) diff --git a/DRAMSys/library/resources/configs/mcconfigs/fifo.xml b/DRAMSys/library/resources/configs/mcconfigs/fifo.xml index 73231bba..d01b9248 100644 --- a/DRAMSys/library/resources/configs/mcconfigs/fifo.xml +++ b/DRAMSys/library/resources/configs/mcconfigs/fifo.xml @@ -1,7 +1,7 @@ - + diff --git a/DRAMSys/library/resources/configs/mcconfigs/fifoStrict.xml b/DRAMSys/library/resources/configs/mcconfigs/fifoStrict.xml index dee4f5d4..ed869b57 100644 --- a/DRAMSys/library/resources/configs/mcconfigs/fifoStrict.xml +++ b/DRAMSys/library/resources/configs/mcconfigs/fifoStrict.xml @@ -1,7 +1,7 @@ - + diff --git a/DRAMSys/library/resources/configs/mcconfigs/fifo_ecc.xml b/DRAMSys/library/resources/configs/mcconfigs/fifo_ecc.xml index 73231bba..d01b9248 100644 --- a/DRAMSys/library/resources/configs/mcconfigs/fifo_ecc.xml +++ b/DRAMSys/library/resources/configs/mcconfigs/fifo_ecc.xml @@ -1,7 +1,7 @@ - + diff --git a/DRAMSys/library/resources/configs/mcconfigs/fr_fcfs.xml b/DRAMSys/library/resources/configs/mcconfigs/fr_fcfs.xml index e5a6579e..20db08cd 100644 --- a/DRAMSys/library/resources/configs/mcconfigs/fr_fcfs.xml +++ b/DRAMSys/library/resources/configs/mcconfigs/fr_fcfs.xml @@ -1,7 +1,7 @@ - + diff --git a/DRAMSys/library/resources/configs/mcconfigs/fr_fcfs_grp.xml b/DRAMSys/library/resources/configs/mcconfigs/fr_fcfs_grp.xml index 75570d40..dad77bf6 100644 --- a/DRAMSys/library/resources/configs/mcconfigs/fr_fcfs_grp.xml +++ b/DRAMSys/library/resources/configs/mcconfigs/fr_fcfs_grp.xml @@ -1,7 +1,7 @@ - + diff --git a/DRAMSys/library/resources/configs/mcconfigs/fr_fcfs_rp.xml b/DRAMSys/library/resources/configs/mcconfigs/fr_fcfs_rp.xml index 5a9f1c0c..3f636ba0 100644 --- a/DRAMSys/library/resources/configs/mcconfigs/fr_fcfs_rp.xml +++ b/DRAMSys/library/resources/configs/mcconfigs/fr_fcfs_rp.xml @@ -1,7 +1,7 @@ - + diff --git a/DRAMSys/library/resources/configs/mcconfigs/grp.xml b/DRAMSys/library/resources/configs/mcconfigs/grp.xml index a62969fb..753cca46 100644 --- a/DRAMSys/library/resources/configs/mcconfigs/grp.xml +++ b/DRAMSys/library/resources/configs/mcconfigs/grp.xml @@ -1,7 +1,7 @@ - + diff --git a/DRAMSys/library/resources/configs/mcconfigs/rgrmccfg.xml b/DRAMSys/library/resources/configs/mcconfigs/rgrmccfg.xml index bb8b64ae..b17e59ce 100644 --- a/DRAMSys/library/resources/configs/mcconfigs/rgrmccfg.xml +++ b/DRAMSys/library/resources/configs/mcconfigs/rgrmccfg.xml @@ -1,7 +1,7 @@ - + diff --git a/DRAMSys/library/src/controller/Controller.cpp b/DRAMSys/library/src/controller/Controller.cpp index d9bf6d89..1fac6814 100644 --- a/DRAMSys/library/src/controller/Controller.cpp +++ b/DRAMSys/library/src/controller/Controller.cpp @@ -103,17 +103,17 @@ void Controller::buildScheduler() { string selectedScheduler = Configuration::getInstance().Scheduler; - if (selectedScheduler == "FIFO") { + if (selectedScheduler == "Fifo") { scheduler = new Fifo(*controllerCore); - } else if (selectedScheduler == "FIFO_STRICT") { + } else if (selectedScheduler == "FifoStrict") { scheduler = new FifoStrict(*this, *controllerCore); - } else if (selectedScheduler == "FR_FCFS") { + } else if (selectedScheduler == "FrFcfs") { scheduler = new FrFcfs(*controllerCore); - } else if (selectedScheduler == "FR_FCFS_RP") { + } else if (selectedScheduler == "FrFcfsRp") { scheduler = new FrFcfsRp(*controllerCore); - } else if (selectedScheduler == "FR_FCFS_GRP") { + } else if (selectedScheduler == "FrFcfsGrp") { scheduler = new FrFcfsGrp(*controllerCore, this); - } else if (selectedScheduler == "GRP") { + } else if (selectedScheduler == "Grp") { scheduler = new Grp(*controllerCore, this); } else if (selectedScheduler == "SMS") { scheduler = new SMS("SMS", *controllerCore, diff --git a/DRAMSys/library/src/controller/scheduler/FrFcfs.cpp b/DRAMSys/library/src/controller/scheduler/FrFcfs.cpp index afa12aa2..c0d742af 100644 --- a/DRAMSys/library/src/controller/scheduler/FrFcfs.cpp +++ b/DRAMSys/library/src/controller/scheduler/FrFcfs.cpp @@ -73,7 +73,7 @@ std::pair FrFcfs::getNextRequest(Bank bank) if (buffer[bank].empty()) return std::pair(Command::NOP, NULL); - // In FR_FCFS row hits have always the highest priority, therefore we search + // In FrFcfs row hits have always the highest priority, therefore we search // for row hits. If we find a row hit, we remove the transaction from the // queue and send it to the DRAM. std::deque::iterator it = findRowHit(bank); @@ -84,7 +84,7 @@ std::pair FrFcfs::getNextRequest(Bank bank) return std::pair(getReadWriteCommand(payload), payload); } - // If there is no row hit, the FR_FCFS takes always the oldest transaction + // If there is no row hit, the FrFcfs takes always the oldest transaction // in the buffer, i.e. the transaction in the front. return std::pair(getNextCommand(buffer[bank].front()), buffer[bank].front()); diff --git a/DRAMSys/traceAnalyzer/scripts/tests.py b/DRAMSys/traceAnalyzer/scripts/tests.py index 260853eb..2d3becd9 100755 --- a/DRAMSys/traceAnalyzer/scripts/tests.py +++ b/DRAMSys/traceAnalyzer/scripts/tests.py @@ -713,10 +713,10 @@ def strict_transaction_order(connection): transactions += str(currentRow[0]) + "," if (transactions != ""): - if (dramconfig.scheduler == "FIFO_STRICT"): + if (dramconfig.scheduler == "FifoStrict"): return TestFailed("Transactions {0} is/are not in Order ".format(transactions)) else: - return TestResult(True, "Transactions are not in Order, however this is okay since no FIFO_STRICT was choosen") + return TestResult(True, "Transactions are not in Order, however this is okay since no FifoStrict was choosen") return TestSuceeded() # ----------- powerdown checks --------------------------------------- diff --git a/README.md b/README.md index c23d501e..42b094de 100644 --- a/README.md +++ b/README.md @@ -706,7 +706,7 @@ Below, the sub-configurations are listed and explained. - + @@ -764,9 +764,13 @@ Below, the sub-configurations are listed and explained. - *MaxNrOfTransactions* (unsigned int) - Maximum number of transactions. - *Scheduler* (string) - - "FIFO": first in, first out - - "FIFO_STRICT": out-of-order treatment of queue elements not allowed - - "FR_FCFS": first-come, first-served + - "Fifo": first in, first out + - "FifoStrict": out-of-order treatment of queue elements not allowed + - "FrFcfs": first ready first-come-first-served + - "FrFcfsRp": first ready first-come-first-served read priority + - "FrFcfsGrp": first ready first-come-first-served grouper + - "Grp": grouper + - "SMS": will be removed - *Capsize* (unsigned int) - Capacitor cell size. - *PowerDownMode* (enum EPowerDownMode) @@ -1410,7 +1414,7 @@ Enable the error model in fr_fcfs.xml. - + From cff2455be255f2042e0fd250d3fa5ded3fc1693e Mon Sep 17 00:00:00 2001 From: Lukas Steiner Date: Sat, 22 Jun 2019 22:08:00 +0200 Subject: [PATCH 91/97] Bugfix for failing tests: missing renaming. --- DRAMSys/tests/DDR3/configs/mcconfigs/fifoStrict.xml | 2 +- DRAMSys/tests/DDR3/configs/mcconfigs/fr_fcfs.xml | 2 +- DRAMSys/tests/TLM_compliance/fifoStrict.xml | 2 +- DRAMSys/tests/WIDEIO/configs/mcconfigs/fifoStrict.xml | 2 +- DRAMSys/tests/error/fr_fcfs.xml | 2 +- DRAMSys/tests/simple/fifoStrict.xml | 2 +- DRAMSys/tests/timing_compliance/fifoStrict.xml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/DRAMSys/tests/DDR3/configs/mcconfigs/fifoStrict.xml b/DRAMSys/tests/DDR3/configs/mcconfigs/fifoStrict.xml index dee4f5d4..ed869b57 100644 --- a/DRAMSys/tests/DDR3/configs/mcconfigs/fifoStrict.xml +++ b/DRAMSys/tests/DDR3/configs/mcconfigs/fifoStrict.xml @@ -1,7 +1,7 @@ - + diff --git a/DRAMSys/tests/DDR3/configs/mcconfigs/fr_fcfs.xml b/DRAMSys/tests/DDR3/configs/mcconfigs/fr_fcfs.xml index e5a6579e..20db08cd 100644 --- a/DRAMSys/tests/DDR3/configs/mcconfigs/fr_fcfs.xml +++ b/DRAMSys/tests/DDR3/configs/mcconfigs/fr_fcfs.xml @@ -1,7 +1,7 @@ - + diff --git a/DRAMSys/tests/TLM_compliance/fifoStrict.xml b/DRAMSys/tests/TLM_compliance/fifoStrict.xml index d5814755..440f465a 100644 --- a/DRAMSys/tests/TLM_compliance/fifoStrict.xml +++ b/DRAMSys/tests/TLM_compliance/fifoStrict.xml @@ -2,7 +2,7 @@ - + diff --git a/DRAMSys/tests/WIDEIO/configs/mcconfigs/fifoStrict.xml b/DRAMSys/tests/WIDEIO/configs/mcconfigs/fifoStrict.xml index dee4f5d4..ed869b57 100644 --- a/DRAMSys/tests/WIDEIO/configs/mcconfigs/fifoStrict.xml +++ b/DRAMSys/tests/WIDEIO/configs/mcconfigs/fifoStrict.xml @@ -1,7 +1,7 @@ - + diff --git a/DRAMSys/tests/error/fr_fcfs.xml b/DRAMSys/tests/error/fr_fcfs.xml index c2861799..9066796c 100644 --- a/DRAMSys/tests/error/fr_fcfs.xml +++ b/DRAMSys/tests/error/fr_fcfs.xml @@ -2,7 +2,7 @@ - + diff --git a/DRAMSys/tests/simple/fifoStrict.xml b/DRAMSys/tests/simple/fifoStrict.xml index 43744c7d..247c4de3 100644 --- a/DRAMSys/tests/simple/fifoStrict.xml +++ b/DRAMSys/tests/simple/fifoStrict.xml @@ -2,7 +2,7 @@ - + diff --git a/DRAMSys/tests/timing_compliance/fifoStrict.xml b/DRAMSys/tests/timing_compliance/fifoStrict.xml index 2c84267e..fc213074 100644 --- a/DRAMSys/tests/timing_compliance/fifoStrict.xml +++ b/DRAMSys/tests/timing_compliance/fifoStrict.xml @@ -2,7 +2,7 @@ - + From cb7b5b585ad238d97d8064eedd07dad41a336360 Mon Sep 17 00:00:00 2001 From: "Lukas Steiner (2)" Date: Sun, 23 Jun 2019 19:10:28 +0200 Subject: [PATCH 92/97] NOT RUNNING! Adapting current DRAM to new structure. --- DRAMSys/library/library.pro | 6 +- DRAMSys/library/src/simulation/DRAMSys.cpp | 3 +- DRAMSys/library/src/simulation/DramDDR3.h | 2 + DRAMSys/library/src/simulation/DramDDR4.h | 6 ++ .../library/src/simulation/DramRecordable.cpp | 96 ++++++++++++++++++- .../library/src/simulation/DramRecordable.h | 29 ++++++ .../src/simulation/DramRecordablePower.cpp | 47 --------- .../src/simulation/DramRecordablePower.h | 50 ---------- 8 files changed, 132 insertions(+), 107 deletions(-) delete mode 100644 DRAMSys/library/src/simulation/DramRecordablePower.cpp delete mode 100644 DRAMSys/library/src/simulation/DramRecordablePower.h diff --git a/DRAMSys/library/library.pro b/DRAMSys/library/library.pro index 6fbf6467..dabae60c 100644 --- a/DRAMSys/library/library.pro +++ b/DRAMSys/library/library.pro @@ -146,8 +146,7 @@ SOURCES += \ src/common/utils.cpp \ src/simulation/DramDDR3.cpp \ src/simulation/DramDDR4.cpp \ - src/simulation/DramRecordable.cpp \ - src/simulation/DramRecordablePower.cpp + src/simulation/DramRecordable.cpp HEADERS += \ src/common/third_party/tinyxml2/tinyxml2.h \ @@ -227,8 +226,7 @@ HEADERS += \ src/controller/core/configuration/TemperatureSimConfig.h \ src/simulation/DramDDR3.h \ src/simulation/DramDDR4.h \ - src/simulation/DramRecordable.h \ - src/simulation/DramRecordablePower.h + src/simulation/DramRecordable.h #src/common/third_party/json/include/nlohmann/json.hpp \ thermalsim = $$(THERMALSIM) diff --git a/DRAMSys/library/src/simulation/DRAMSys.cpp b/DRAMSys/library/src/simulation/DRAMSys.cpp index 563c2a41..61fbfc63 100644 --- a/DRAMSys/library/src/simulation/DRAMSys.cpp +++ b/DRAMSys/library/src/simulation/DRAMSys.cpp @@ -55,7 +55,6 @@ #include "../controller/Controller.h" #include "../error/ecchamming.h" #include "DramRecordable.h" -#include "DramRecordablePower.h" #include "DramDDR3.h" #include "RecordableDram.h" @@ -264,7 +263,7 @@ void DRAMSys::instantiateModules(const string &traceName, Dram *dram; if (recordingEnabled) //dram = new RecordableDram(str.c_str(), tlmRecorders[i]); - dram = new DramRecordablePower(str.c_str(), tlmRecorders[i]); + dram = new DramRecordable(str.c_str(), tlmRecorders[i]); else dram = new Dram(str.c_str()); drams.push_back(dram); diff --git a/DRAMSys/library/src/simulation/DramDDR3.h b/DRAMSys/library/src/simulation/DramDDR3.h index c1aa87ca..894809bb 100644 --- a/DRAMSys/library/src/simulation/DramDDR3.h +++ b/DRAMSys/library/src/simulation/DramDDR3.h @@ -43,6 +43,8 @@ class DramDDR3 : public Dram public: DramDDR3(sc_module_name); SC_HAS_PROCESS(DramDDR3); + + ~DramDDR3(); }; #endif // DRAMDDR3_H diff --git a/DRAMSys/library/src/simulation/DramDDR4.h b/DRAMSys/library/src/simulation/DramDDR4.h index 855a3aaf..ed884bc1 100644 --- a/DRAMSys/library/src/simulation/DramDDR4.h +++ b/DRAMSys/library/src/simulation/DramDDR4.h @@ -2,12 +2,18 @@ #define DRAMDDR4_H #include "Dram.h" +#include "systemc" +#include "tlm" + +using namespace tlm; class DramDDR4 : public Dram { public: DramDDR4(sc_module_name); SC_HAS_PROCESS(DramDDR4); + + ~DramDDR4(); }; #endif // DRAMDDR4_H diff --git a/DRAMSys/library/src/simulation/DramRecordable.cpp b/DRAMSys/library/src/simulation/DramRecordable.cpp index 9b1fec3c..d7312d5c 100644 --- a/DRAMSys/library/src/simulation/DramRecordable.cpp +++ b/DRAMSys/library/src/simulation/DramRecordable.cpp @@ -34,14 +34,102 @@ */ #include "DramRecordable.h" -#include "RecordableDram.h" +#include "Dram.h" + +using namespace tlm; template DramRecordable::DramRecordable(sc_module_name name, TlmRecorder *tlmRecorder) - : BaseDram(name, tlmRecorder) + : BaseDram(name), tlmRecorder(tlmRecorder) { - + // Create a thread that is triggered every $powerWindowSize + // to generate a Power over Time plot in the Trace analyzer: + SC_THREAD(powerWindow); } -template class DramRecordable; +template +DramRecordable::~DramRecordable() +{ + BaseDram::DRAMPower->calcEnergy(); + recordPower(); + tlmRecorder->closeConnection(); +} + +template +tlm_sync_enum DramRecordable::nb_transport_fw(tlm_generic_payload &payload, + tlm_phase &phase, sc_time &delay) +{ + // Recording time used by the traceAnalyzer + sc_time recTime = sc_time_stamp() + delay; + + // These are terminating phases recorded by the DRAM. The execution + // time of the related command must be taken into consideration. + if (phase == END_PDNA || phase == END_PDNAB) + recTime += getExecutionTime(Command::PDNAX, payload); + else if (phase == END_PDNP || phase == END_PDNPB) + recTime += getExecutionTime(Command::PDNPX, payload); + else if (phase == END_SREF || phase == END_SREFB) + recTime += getExecutionTime(Command::SREFX, payload); + + unsigned int thr = DramExtension::getExtension(payload).getThread().ID(); + unsigned int ch = DramExtension::getExtension(payload).getChannel().ID(); + unsigned int bg = DramExtension::getExtension(payload).getBankGroup().ID(); + unsigned int bank = DramExtension::getExtension(payload).getBank().ID(); + unsigned int row = DramExtension::getExtension(payload).getRow().ID(); + unsigned int col = DramExtension::getExtension(payload).getColumn().ID(); + + // TODO: printDebugMessage not inherited + printDebugMessage("Recording " + phaseNameToString(phase) + " thread " + + to_string(thr) + " channel " + to_string(ch) + " bank group " + to_string( + bg) + " bank " + to_string(bank) + " row " + to_string(row) + " column " + + to_string(col) + " at " + recTime.to_string()); + + tlmRecorder->recordPhase(payload, phase, recTime); + + return BaseDram::nb_transport_fw(payload, phase, delay); +} + +// This Thread is only triggered when Power Simulation is enabled. +// It estimates the current average power which will be stored in the trace database for visualization purposes. +template +void DramRecordable::powerWindow() +{ + unsigned long long clkCycles = 0; + + do { + // At the very beginning (zero clock cycles) the energy is 0, so we wait first + wait(powerWindowSize); + + clkCycles = sc_time_stamp().value() / + Configuration::getInstance().memSpec->clk.value(); + + DRAMPower->calcWindowEnergy(clkCycles); + + // During operation the energy should never be zero since the device is always consuming + assert(!isEqual(DRAMPower->getEnergy().window_energy, 0.0)); + + // Store the time (in seconds) and the current average power (in mW) into the database + recordPower(); + + // Here considering that DRAMPower provides the energy in pJ and the power in mW + printDebugMessage(string("\tWindow Energy: \t") + to_string( + DRAMPower->getEnergy().window_energy * + Configuration::getInstance().NumberOfDevicesOnDIMM) + string("\t[pJ]")); + printDebugMessage(string("\tWindow Average Power: \t") + to_string( + DRAMPower->getPower().window_average_power * + Configuration::getInstance().NumberOfDevicesOnDIMM) + string("\t[mW]")); + + } while (true); +} + +template +void DramRecordable::recordPower() +{ + tlmRecorder->recordPower(sc_time_stamp().to_seconds(), + DRAMPower->getPower().window_average_power + * Configuration::getInstance().NumberOfDevicesOnDIMM); +} + + +template class DramRecordable; diff --git a/DRAMSys/library/src/simulation/DramRecordable.h b/DRAMSys/library/src/simulation/DramRecordable.h index 95139b1f..2e4231ff 100644 --- a/DRAMSys/library/src/simulation/DramRecordable.h +++ b/DRAMSys/library/src/simulation/DramRecordable.h @@ -36,17 +36,46 @@ #ifndef DRAMRECORDABLE_H #define DRAMRECORDABLE_H +#include +#include #include "DramDDR3.h" #include "DramDDR4.h" #include "RecordableDram.h" #include "../common/TlmRecorder.h" +using namespace tlm; + template class DramRecordable : public BaseDram { public: DramRecordable(sc_module_name name, TlmRecorder *tlmRecorder); SC_HAS_PROCESS(DramRecordable); + + ~DramRecordable(); + +protected: + virtual tlm_sync_enum nb_transport_fw(tlm_generic_payload &payload, + tlm_phase &phase, sc_time &delay); + +private: + TlmRecorder *tlmRecorder; + sc_time powerWindowSize = Configuration::getInstance().memSpec->clk * + Configuration::getInstance().WindowSize; + + // When working with floats, we have to decide ourselves what is an + // acceptable definition for "equal". Here the number is compared with a + // suitable error margin (0.00001). + bool isEqual(double a, double b, const double epsilon = 1e-05) + { + return std::fabs(a - b) < epsilon; + } + + // This Thread is only triggered when Power Simulation is enabled. + // It estimates the current average power which will be stored in the trace database for visualization purposes. + void powerWindow(); + + void recordPower(); }; #endif // DRAMRECORDABLE_H diff --git a/DRAMSys/library/src/simulation/DramRecordablePower.cpp b/DRAMSys/library/src/simulation/DramRecordablePower.cpp deleted file mode 100644 index bc855e77..00000000 --- a/DRAMSys/library/src/simulation/DramRecordablePower.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2019, University of Kaiserslautern - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: - * Lukas Steiner - */ - -#include "DramRecordablePower.h" -#include "RecordableDram.h" - -template -DramRecordablePower::DramRecordablePower - (sc_module_name name, TlmRecorder *tlmRecorder) - : DramRecordable(name, tlmRecorder) -{ - -} - -template class DramRecordablePower; diff --git a/DRAMSys/library/src/simulation/DramRecordablePower.h b/DRAMSys/library/src/simulation/DramRecordablePower.h deleted file mode 100644 index b38dacb2..00000000 --- a/DRAMSys/library/src/simulation/DramRecordablePower.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2019, University of Kaiserslautern - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: - * Lukas Steiner - */ - -#ifndef DRAMRECORDABLEPOWER_H -#define DRAMRECORDABLEPOWER_H - -#include "DramRecordable.h" -#include "../common/TlmRecorder.h" - -template -class DramRecordablePower : public DramRecordable -{ -public: - DramRecordablePower(sc_module_name name, TlmRecorder *tlmRecorder); - SC_HAS_PROCESS(DramRecordablePower); -}; - -#endif // DRAMRECORDABLEPOWER_H From f8baef57c6532a144373a36ed7e7dc77078b1a31 Mon Sep 17 00:00:00 2001 From: Lukas Steiner Date: Sun, 23 Jun 2019 20:53:08 +0200 Subject: [PATCH 93/97] Adapting current DRAM to new structure. --- DRAMSys/library/src/simulation/DRAMSys.cpp | 3 +- DRAMSys/library/src/simulation/DramDDR3.cpp | 2 + DRAMSys/library/src/simulation/DramDDR3.h | 4 +- DRAMSys/library/src/simulation/DramDDR4.cpp | 2 + DRAMSys/library/src/simulation/DramDDR4.h | 41 +++++++++++++++++-- .../library/src/simulation/DramRecordable.cpp | 26 +++++++----- 6 files changed, 63 insertions(+), 15 deletions(-) diff --git a/DRAMSys/library/src/simulation/DRAMSys.cpp b/DRAMSys/library/src/simulation/DRAMSys.cpp index 61fbfc63..d4e37757 100644 --- a/DRAMSys/library/src/simulation/DRAMSys.cpp +++ b/DRAMSys/library/src/simulation/DRAMSys.cpp @@ -56,6 +56,7 @@ #include "../error/ecchamming.h" #include "DramRecordable.h" #include "DramDDR3.h" +#include "DramDDR4.h" #include "RecordableDram.h" using namespace std; @@ -263,7 +264,7 @@ void DRAMSys::instantiateModules(const string &traceName, Dram *dram; if (recordingEnabled) //dram = new RecordableDram(str.c_str(), tlmRecorders[i]); - dram = new DramRecordable(str.c_str(), tlmRecorders[i]); + dram = new DramRecordable(str.c_str(), tlmRecorders[i]); else dram = new Dram(str.c_str()); drams.push_back(dram); diff --git a/DRAMSys/library/src/simulation/DramDDR3.cpp b/DRAMSys/library/src/simulation/DramDDR3.cpp index 416f7c63..91ba5736 100644 --- a/DRAMSys/library/src/simulation/DramDDR3.cpp +++ b/DRAMSys/library/src/simulation/DramDDR3.cpp @@ -40,3 +40,5 @@ DramDDR3::DramDDR3(sc_module_name name) : Dram(name) { } + +//DramDDR3::~DramDDR3() {} diff --git a/DRAMSys/library/src/simulation/DramDDR3.h b/DRAMSys/library/src/simulation/DramDDR3.h index 894809bb..0bf0a8a9 100644 --- a/DRAMSys/library/src/simulation/DramDDR3.h +++ b/DRAMSys/library/src/simulation/DramDDR3.h @@ -37,6 +37,8 @@ #define DRAMDDR3_H #include "Dram.h" +#include +#include class DramDDR3 : public Dram { @@ -44,7 +46,7 @@ public: DramDDR3(sc_module_name); SC_HAS_PROCESS(DramDDR3); - ~DramDDR3(); + //~DramDDR3(); }; #endif // DRAMDDR3_H diff --git a/DRAMSys/library/src/simulation/DramDDR4.cpp b/DRAMSys/library/src/simulation/DramDDR4.cpp index 4eb6bb39..b10cd313 100644 --- a/DRAMSys/library/src/simulation/DramDDR4.cpp +++ b/DRAMSys/library/src/simulation/DramDDR4.cpp @@ -40,3 +40,5 @@ DramDDR4::DramDDR4(sc_module_name name) : Dram(name) { } + +//DramDDR4::~DramDDR4() {} diff --git a/DRAMSys/library/src/simulation/DramDDR4.h b/DRAMSys/library/src/simulation/DramDDR4.h index ed884bc1..64bae19d 100644 --- a/DRAMSys/library/src/simulation/DramDDR4.h +++ b/DRAMSys/library/src/simulation/DramDDR4.h @@ -1,9 +1,44 @@ +/* + * Copyright (c) 2019, University of Kaiserslautern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: + * Lukas Steiner + */ + #ifndef DRAMDDR4_H #define DRAMDDR4_H #include "Dram.h" -#include "systemc" -#include "tlm" +#include +#include using namespace tlm; @@ -13,7 +48,7 @@ public: DramDDR4(sc_module_name); SC_HAS_PROCESS(DramDDR4); - ~DramDDR4(); + //~DramDDR4(); }; #endif // DRAMDDR4_H diff --git a/DRAMSys/library/src/simulation/DramRecordable.cpp b/DRAMSys/library/src/simulation/DramRecordable.cpp index d7312d5c..e9adc271 100644 --- a/DRAMSys/library/src/simulation/DramRecordable.cpp +++ b/DRAMSys/library/src/simulation/DramRecordable.cpp @@ -34,7 +34,12 @@ */ #include "DramRecordable.h" -#include "Dram.h" +#include +#include +#include "../common/TlmRecorder.h" +#include "DramDDR3.h" +#include "DramDDR4.h" +#include "../common/utils.h" using namespace tlm; @@ -79,7 +84,7 @@ tlm_sync_enum DramRecordable::nb_transport_fw(tlm_generic_payload &pay unsigned int col = DramExtension::getExtension(payload).getColumn().ID(); // TODO: printDebugMessage not inherited - printDebugMessage("Recording " + phaseNameToString(phase) + " thread " + + BaseDram::printDebugMessage("Recording " + phaseNameToString(phase) + " thread " + to_string(thr) + " channel " + to_string(ch) + " bank group " + to_string( bg) + " bank " + to_string(bank) + " row " + to_string(row) + " column " + to_string(col) + " at " + recTime.to_string()); @@ -103,20 +108,20 @@ void DramRecordable::powerWindow() clkCycles = sc_time_stamp().value() / Configuration::getInstance().memSpec->clk.value(); - DRAMPower->calcWindowEnergy(clkCycles); + BaseDram::DRAMPower->calcWindowEnergy(clkCycles); // During operation the energy should never be zero since the device is always consuming - assert(!isEqual(DRAMPower->getEnergy().window_energy, 0.0)); + assert(!isEqual(BaseDram::DRAMPower->getEnergy().window_energy, 0.0)); // Store the time (in seconds) and the current average power (in mW) into the database recordPower(); // Here considering that DRAMPower provides the energy in pJ and the power in mW - printDebugMessage(string("\tWindow Energy: \t") + to_string( - DRAMPower->getEnergy().window_energy * + BaseDram::printDebugMessage(string("\tWindow Energy: \t") + to_string( + BaseDram::DRAMPower->getEnergy().window_energy * Configuration::getInstance().NumberOfDevicesOnDIMM) + string("\t[pJ]")); - printDebugMessage(string("\tWindow Average Power: \t") + to_string( - DRAMPower->getPower().window_average_power * + BaseDram::printDebugMessage(string("\tWindow Average Power: \t") + to_string( + BaseDram::DRAMPower->getPower().window_average_power * Configuration::getInstance().NumberOfDevicesOnDIMM) + string("\t[mW]")); } while (true); @@ -126,10 +131,11 @@ template void DramRecordable::recordPower() { tlmRecorder->recordPower(sc_time_stamp().to_seconds(), - DRAMPower->getPower().window_average_power + BaseDram::DRAMPower->getPower().window_average_power * Configuration::getInstance().NumberOfDevicesOnDIMM); } -template class DramRecordable; +template class DramRecordable; +template class DramRecordable; From 21c243b9d317d4b0f35733e097e18be5837473a9 Mon Sep 17 00:00:00 2001 From: Lukas Steiner Date: Sun, 23 Jun 2019 21:20:21 +0200 Subject: [PATCH 94/97] Replaced "BaseDram::" with "this->" to access members of the base class. --- .../library/src/simulation/DramRecordable.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/DRAMSys/library/src/simulation/DramRecordable.cpp b/DRAMSys/library/src/simulation/DramRecordable.cpp index e9adc271..56a3196a 100644 --- a/DRAMSys/library/src/simulation/DramRecordable.cpp +++ b/DRAMSys/library/src/simulation/DramRecordable.cpp @@ -84,7 +84,7 @@ tlm_sync_enum DramRecordable::nb_transport_fw(tlm_generic_payload &pay unsigned int col = DramExtension::getExtension(payload).getColumn().ID(); // TODO: printDebugMessage not inherited - BaseDram::printDebugMessage("Recording " + phaseNameToString(phase) + " thread " + + this->printDebugMessage("Recording " + phaseNameToString(phase) + " thread " + to_string(thr) + " channel " + to_string(ch) + " bank group " + to_string( bg) + " bank " + to_string(bank) + " row " + to_string(row) + " column " + to_string(col) + " at " + recTime.to_string()); @@ -108,20 +108,20 @@ void DramRecordable::powerWindow() clkCycles = sc_time_stamp().value() / Configuration::getInstance().memSpec->clk.value(); - BaseDram::DRAMPower->calcWindowEnergy(clkCycles); + this->DRAMPower->calcWindowEnergy(clkCycles); // During operation the energy should never be zero since the device is always consuming - assert(!isEqual(BaseDram::DRAMPower->getEnergy().window_energy, 0.0)); + assert(!isEqual(this->DRAMPower->getEnergy().window_energy, 0.0)); // Store the time (in seconds) and the current average power (in mW) into the database recordPower(); // Here considering that DRAMPower provides the energy in pJ and the power in mW - BaseDram::printDebugMessage(string("\tWindow Energy: \t") + to_string( - BaseDram::DRAMPower->getEnergy().window_energy * + this->printDebugMessage(string("\tWindow Energy: \t") + to_string( + this->DRAMPower->getEnergy().window_energy * Configuration::getInstance().NumberOfDevicesOnDIMM) + string("\t[pJ]")); - BaseDram::printDebugMessage(string("\tWindow Average Power: \t") + to_string( - BaseDram::DRAMPower->getPower().window_average_power * + this->printDebugMessage(string("\tWindow Average Power: \t") + to_string( + this->DRAMPower->getPower().window_average_power * Configuration::getInstance().NumberOfDevicesOnDIMM) + string("\t[mW]")); } while (true); @@ -131,7 +131,7 @@ template void DramRecordable::recordPower() { tlmRecorder->recordPower(sc_time_stamp().to_seconds(), - BaseDram::DRAMPower->getPower().window_average_power + this->DRAMPower->getPower().window_average_power * Configuration::getInstance().NumberOfDevicesOnDIMM); } From 45b05c5cf0e0f6bbe6a04d53871505fb74fb928f Mon Sep 17 00:00:00 2001 From: "Lukas Steiner (2)" Date: Mon, 24 Jun 2019 11:59:59 +0200 Subject: [PATCH 95/97] Created DramWideIO, removed powerAnalysis switch. --- DRAMSys/library/library.pro | 6 +- DRAMSys/library/src/simulation/DRAMSys.cpp | 33 +- DRAMSys/library/src/simulation/Dram.cpp | 407 +++++++----------- DRAMSys/library/src/simulation/Dram.h | 11 +- DRAMSys/library/src/simulation/DramDDR3.cpp | 7 +- DRAMSys/library/src/simulation/DramDDR3.h | 2 - DRAMSys/library/src/simulation/DramDDR4.cpp | 7 +- DRAMSys/library/src/simulation/DramDDR4.h | 4 - .../library/src/simulation/DramRecordable.cpp | 2 + .../library/src/simulation/DramRecordable.h | 2 +- DRAMSys/library/src/simulation/DramWideIO.cpp | 251 +++++++++++ DRAMSys/library/src/simulation/DramWideIO.h | 62 +++ 12 files changed, 503 insertions(+), 291 deletions(-) create mode 100644 DRAMSys/library/src/simulation/DramWideIO.cpp create mode 100644 DRAMSys/library/src/simulation/DramWideIO.h diff --git a/DRAMSys/library/library.pro b/DRAMSys/library/library.pro index dabae60c..05098c1f 100644 --- a/DRAMSys/library/library.pro +++ b/DRAMSys/library/library.pro @@ -146,7 +146,8 @@ SOURCES += \ src/common/utils.cpp \ src/simulation/DramDDR3.cpp \ src/simulation/DramDDR4.cpp \ - src/simulation/DramRecordable.cpp + src/simulation/DramRecordable.cpp \ + src/simulation/DramWideIO.cpp HEADERS += \ src/common/third_party/tinyxml2/tinyxml2.h \ @@ -226,7 +227,8 @@ HEADERS += \ src/controller/core/configuration/TemperatureSimConfig.h \ src/simulation/DramDDR3.h \ src/simulation/DramDDR4.h \ - src/simulation/DramRecordable.h + src/simulation/DramRecordable.h \ + src/simulation/DramWideIO.h #src/common/third_party/json/include/nlohmann/json.hpp \ thermalsim = $$(THERMALSIM) diff --git a/DRAMSys/library/src/simulation/DRAMSys.cpp b/DRAMSys/library/src/simulation/DRAMSys.cpp index d4e37757..437c5ff2 100644 --- a/DRAMSys/library/src/simulation/DRAMSys.cpp +++ b/DRAMSys/library/src/simulation/DRAMSys.cpp @@ -57,6 +57,7 @@ #include "DramRecordable.h" #include "DramDDR3.h" #include "DramDDR4.h" +#include "DramWideIO.h" #include "RecordableDram.h" using namespace std; @@ -244,10 +245,9 @@ void DRAMSys::instantiateModules(const string &traceName, // Create arbiter arbiter = new Arbiter("arbiter"); - std::string testString = "test"; - //DramRecordable testDram(testString.c_str(), tlmRecorders[0]); // Create DRAM + std::string memoryType = Configuration::getInstance().memSpec->MemoryType; for (size_t i = 0; i < Configuration::getInstance().NumberOfMemChannels; i++) { @@ -262,11 +262,32 @@ void DRAMSys::instantiateModules(const string &traceName, str = "dram" + std::to_string(i); Dram *dram; - if (recordingEnabled) - //dram = new RecordableDram(str.c_str(), tlmRecorders[i]); - dram = new DramRecordable(str.c_str(), tlmRecorders[i]); + + if (memoryType == "DDR3") + { + if (recordingEnabled) + dram = new DramRecordable(str.c_str(), tlmRecorders[i]); + else + dram = new DramDDR3(str.c_str()); + } + else if (memoryType == "DDR4") + { + if (recordingEnabled) + dram = new DramRecordable(str.c_str(), tlmRecorders[i]); + else + dram = new DramDDR4(str.c_str()); + } + else if (memoryType == "WIDEIO_SDR") + { + if (recordingEnabled) + dram = new DramRecordable(str.c_str(), tlmRecorders[i]); + else + dram = new DramWideIO(str.c_str()); + } else - dram = new Dram(str.c_str()); + { + SC_REPORT_FATAL("DRAMSys", "Unsupported DRAM type"); + } drams.push_back(dram); if (Configuration::getInstance().CheckTLM2Protocol) { diff --git a/DRAMSys/library/src/simulation/Dram.cpp b/DRAMSys/library/src/simulation/Dram.cpp index 5b6c3901..af3a1594 100644 --- a/DRAMSys/library/src/simulation/Dram.cpp +++ b/DRAMSys/library/src/simulation/Dram.cpp @@ -62,180 +62,139 @@ using namespace std; using namespace tlm; using namespace Data; - Dram::Dram(sc_module_name) : tSocket("socket") { // Adjust number of bytes per burst dynamically to the selected ecc controller - bytesPerBurst = Configuration::getInstance().adjustNumBytesAfterECC( - bytesPerBurst); - - std::uint64_t memorySize = Configuration::getInstance().getSimMemSizeInBytes(); - if (Configuration::getInstance().UseMalloc) - { - memory = (unsigned char *)malloc(memorySize); - if (!memory) - { - SC_REPORT_FATAL(this->name(), "Memory allocation failed"); - } - } - else - { - // 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); - } + bytesPerBurst = Configuration::getInstance() + .adjustNumBytesAfterECC(bytesPerBurst); tSocket.register_nb_transport_fw(this, &Dram::nb_transport_fw); tSocket.register_transport_dbg(this, &Dram::transport_dbg); - if (powerAnalysis) - { - sc_time clk = Configuration::getInstance().memSpec->clk; + // Parameters for DRAMPower + sc_time clk = Configuration::getInstance().memSpec->clk; - MemArchitectureSpec memArchSpec; - memArchSpec.burstLength = - Configuration::getInstance().memSpec->BurstLength; - memArchSpec.dataRate = Configuration::getInstance().memSpec->DataRate; - memArchSpec.nbrOfRows = - Configuration::getInstance().memSpec->NumberOfRows; - memArchSpec.nbrOfBanks = - Configuration::getInstance().memSpec->NumberOfBanks; - memArchSpec.nbrOfColumns = - Configuration::getInstance().memSpec->NumberOfColumns; - memArchSpec.nbrOfRanks = - Configuration::getInstance().memSpec->NumberOfRanks; - memArchSpec.width = Configuration::getInstance().memSpec->bitWidth; - memArchSpec.nbrOfBankGroups = - Configuration::getInstance().memSpec->NumberOfBankGroups; - memArchSpec.twoVoltageDomains = (Configuration::getInstance().memSpec->vDD2 == 0 - ? false : true); - memArchSpec.dll = Configuration::getInstance().memSpec->DLL; + MemArchitectureSpec memArchSpec; + memArchSpec.burstLength = + Configuration::getInstance().memSpec->BurstLength; + memArchSpec.dataRate = Configuration::getInstance().memSpec->DataRate; + memArchSpec.nbrOfRows = + Configuration::getInstance().memSpec->NumberOfRows; + memArchSpec.nbrOfBanks = + Configuration::getInstance().memSpec->NumberOfBanks; + memArchSpec.nbrOfColumns = + Configuration::getInstance().memSpec->NumberOfColumns; + memArchSpec.nbrOfRanks = + Configuration::getInstance().memSpec->NumberOfRanks; + memArchSpec.width = Configuration::getInstance().memSpec->bitWidth; + memArchSpec.nbrOfBankGroups = + Configuration::getInstance().memSpec->NumberOfBankGroups; + memArchSpec.twoVoltageDomains = (Configuration::getInstance().memSpec->vDD2 == 0 + ? false : true); + memArchSpec.dll = Configuration::getInstance().memSpec->DLL; - MemTimingSpec memTimingSpec; - memTimingSpec.FAWB = Configuration::getInstance().tfawbclk; - memTimingSpec.RASB = Configuration::getInstance().trasbclk; - memTimingSpec.RCB = Configuration::getInstance().trcbclk; - memTimingSpec.RPB = Configuration::getInstance().trpbclk; - memTimingSpec.RRDB = Configuration::getInstance().trrdblclk; - memTimingSpec.RRDB_L = Configuration::getInstance().trrdblclk; - memTimingSpec.RRDB_S = Configuration::getInstance().trrdblclk; - memTimingSpec.AL = Configuration::getInstance().memSpec->tAL / clk; - memTimingSpec.CCD = Configuration::getInstance().memSpec->tCCD_S / clk; - memTimingSpec.CCD_L = Configuration::getInstance().memSpec->tCCD_L / clk; - memTimingSpec.CCD_S = Configuration::getInstance().memSpec->tCCD_S / clk; - memTimingSpec.CKE = Configuration::getInstance().memSpec->tCKE / clk; - memTimingSpec.CKESR = Configuration::getInstance().memSpec->tCKESR / clk; - memTimingSpec.clkMhz = Configuration::getInstance().memSpec->clkMHz; - // See also MemTimingSpec.cc in DRAMPower - memTimingSpec.clkPeriod = 1000.0 / Configuration::getInstance().memSpec->clkMHz; - memTimingSpec.DQSCK = Configuration::getInstance().memSpec->tDQSCK / clk; - memTimingSpec.FAW = Configuration::getInstance().memSpec->tNAW / clk; - memTimingSpec.RAS = Configuration::getInstance().memSpec->tRAS / clk; - memTimingSpec.RC = Configuration::getInstance().memSpec->tRC / clk; - memTimingSpec.RCD = Configuration::getInstance().memSpec->tRCD / clk; - memTimingSpec.REFI = Configuration::getInstance().memSpec->tREFI / clk; - auto m = Configuration::getInstance().getRefMode(); - if (m == 4) - memTimingSpec.RFC = Configuration::getInstance().memSpec->tRFC4 / clk; - else if (m == 2) - memTimingSpec.RFC = Configuration::getInstance().memSpec->tRFC2 / clk; - else - memTimingSpec.RFC = Configuration::getInstance().memSpec->tRFC / clk; - memTimingSpec.RL = Configuration::getInstance().memSpec->tRL / clk; - memTimingSpec.RP = Configuration::getInstance().memSpec->tRP / clk; - memTimingSpec.RRD = Configuration::getInstance().memSpec->tRRD_S / clk; - memTimingSpec.RRD_L = Configuration::getInstance().memSpec->tRRD_L / clk; - memTimingSpec.RRD_S = Configuration::getInstance().memSpec->tRRD_S / clk; - memTimingSpec.RTP = Configuration::getInstance().memSpec->tRTP / clk; - memTimingSpec.TAW = Configuration::getInstance().memSpec->tNAW / clk; - memTimingSpec.WL = Configuration::getInstance().memSpec->tWL / clk; - memTimingSpec.WR = Configuration::getInstance().memSpec->tWR / clk; - memTimingSpec.WTR = Configuration::getInstance().memSpec->tWTR_S / clk; - memTimingSpec.WTR_L = Configuration::getInstance().memSpec->tWTR_L / clk; - memTimingSpec.WTR_S = Configuration::getInstance().memSpec->tWTR_S / clk; - memTimingSpec.XP = Configuration::getInstance().memSpec->tXP / clk; - memTimingSpec.XPDLL = Configuration::getInstance().memSpec->tXPDLL / clk; - memTimingSpec.XS = Configuration::getInstance().memSpec->tXSR / clk; - memTimingSpec.XSDLL = Configuration::getInstance().memSpec->tXSRDLL / clk; + MemTimingSpec memTimingSpec; + memTimingSpec.FAWB = Configuration::getInstance().tfawbclk; + memTimingSpec.RASB = Configuration::getInstance().trasbclk; + memTimingSpec.RCB = Configuration::getInstance().trcbclk; + memTimingSpec.RPB = Configuration::getInstance().trpbclk; + memTimingSpec.RRDB = Configuration::getInstance().trrdblclk; + memTimingSpec.RRDB_L = Configuration::getInstance().trrdblclk; + memTimingSpec.RRDB_S = Configuration::getInstance().trrdblclk; + memTimingSpec.AL = Configuration::getInstance().memSpec->tAL / clk; + memTimingSpec.CCD = Configuration::getInstance().memSpec->tCCD_S / clk; + memTimingSpec.CCD_L = Configuration::getInstance().memSpec->tCCD_L / clk; + memTimingSpec.CCD_S = Configuration::getInstance().memSpec->tCCD_S / clk; + memTimingSpec.CKE = Configuration::getInstance().memSpec->tCKE / clk; + memTimingSpec.CKESR = Configuration::getInstance().memSpec->tCKESR / clk; + memTimingSpec.clkMhz = Configuration::getInstance().memSpec->clkMHz; + // See also MemTimingSpec.cc in DRAMPower + memTimingSpec.clkPeriod = 1000.0 / Configuration::getInstance().memSpec->clkMHz; + memTimingSpec.DQSCK = Configuration::getInstance().memSpec->tDQSCK / clk; + memTimingSpec.FAW = Configuration::getInstance().memSpec->tNAW / clk; + memTimingSpec.RAS = Configuration::getInstance().memSpec->tRAS / clk; + memTimingSpec.RC = Configuration::getInstance().memSpec->tRC / clk; + memTimingSpec.RCD = Configuration::getInstance().memSpec->tRCD / clk; + memTimingSpec.REFI = Configuration::getInstance().memSpec->tREFI / clk; + auto m = Configuration::getInstance().getRefMode(); + if (m == 4) + memTimingSpec.RFC = Configuration::getInstance().memSpec->tRFC4 / clk; + else if (m == 2) + memTimingSpec.RFC = Configuration::getInstance().memSpec->tRFC2 / clk; + else + memTimingSpec.RFC = Configuration::getInstance().memSpec->tRFC / clk; + memTimingSpec.RL = Configuration::getInstance().memSpec->tRL / clk; + memTimingSpec.RP = Configuration::getInstance().memSpec->tRP / clk; + memTimingSpec.RRD = Configuration::getInstance().memSpec->tRRD_S / clk; + memTimingSpec.RRD_L = Configuration::getInstance().memSpec->tRRD_L / clk; + memTimingSpec.RRD_S = Configuration::getInstance().memSpec->tRRD_S / clk; + memTimingSpec.RTP = Configuration::getInstance().memSpec->tRTP / clk; + memTimingSpec.TAW = Configuration::getInstance().memSpec->tNAW / clk; + memTimingSpec.WL = Configuration::getInstance().memSpec->tWL / clk; + memTimingSpec.WR = Configuration::getInstance().memSpec->tWR / clk; + memTimingSpec.WTR = Configuration::getInstance().memSpec->tWTR_S / clk; + memTimingSpec.WTR_L = Configuration::getInstance().memSpec->tWTR_L / clk; + memTimingSpec.WTR_S = Configuration::getInstance().memSpec->tWTR_S / clk; + memTimingSpec.XP = Configuration::getInstance().memSpec->tXP / clk; + memTimingSpec.XPDLL = Configuration::getInstance().memSpec->tXPDLL / clk; + memTimingSpec.XS = Configuration::getInstance().memSpec->tXSR / clk; + memTimingSpec.XSDLL = Configuration::getInstance().memSpec->tXSRDLL / clk; - MemPowerSpec memPowerSpec; - memPowerSpec.idd0 = Configuration::getInstance().memSpec->iDD0; - memPowerSpec.idd02 = Configuration::getInstance().memSpec->iDD02; - memPowerSpec.idd2p0 = Configuration::getInstance().memSpec->iDD2P0; - memPowerSpec.idd2p02 = Configuration::getInstance().memSpec->iDD2P02; - memPowerSpec.idd2p1 = Configuration::getInstance().memSpec->iDD2P1; - memPowerSpec.idd2p12 = Configuration::getInstance().memSpec->iDD2P12; - memPowerSpec.idd2n = Configuration::getInstance().memSpec->iDD2N; - memPowerSpec.idd2n2 = Configuration::getInstance().memSpec->iDD2N2; - memPowerSpec.idd3p0 = Configuration::getInstance().memSpec->iDD3P0; - memPowerSpec.idd3p02 = Configuration::getInstance().memSpec->iDD3P02; - memPowerSpec.idd3p1 = Configuration::getInstance().memSpec->iDD3P1; - memPowerSpec.idd3p12 = Configuration::getInstance().memSpec->iDD3P12; - memPowerSpec.idd3n = Configuration::getInstance().memSpec->iDD3N; - memPowerSpec.idd3n2 = Configuration::getInstance().memSpec->iDD3N2; - memPowerSpec.idd4r = Configuration::getInstance().memSpec->iDD4R; - memPowerSpec.idd4r2 = Configuration::getInstance().memSpec->iDD4R2; - memPowerSpec.idd4w = Configuration::getInstance().memSpec->iDD4W; - memPowerSpec.idd4w2 = Configuration::getInstance().memSpec->iDD4W2; - memPowerSpec.idd5 = Configuration::getInstance().memSpec->iDD5; - memPowerSpec.idd52 = Configuration::getInstance().memSpec->iDD52; - memPowerSpec.idd6 = Configuration::getInstance().memSpec->iDD6; - memPowerSpec.idd62 = Configuration::getInstance().memSpec->iDD62; - memPowerSpec.vdd = Configuration::getInstance().memSpec->vDD; - memPowerSpec.vdd2 = Configuration::getInstance().memSpec->vDD2; + MemPowerSpec memPowerSpec; + memPowerSpec.idd0 = Configuration::getInstance().memSpec->iDD0; + memPowerSpec.idd02 = Configuration::getInstance().memSpec->iDD02; + memPowerSpec.idd2p0 = Configuration::getInstance().memSpec->iDD2P0; + memPowerSpec.idd2p02 = Configuration::getInstance().memSpec->iDD2P02; + memPowerSpec.idd2p1 = Configuration::getInstance().memSpec->iDD2P1; + memPowerSpec.idd2p12 = Configuration::getInstance().memSpec->iDD2P12; + memPowerSpec.idd2n = Configuration::getInstance().memSpec->iDD2N; + memPowerSpec.idd2n2 = Configuration::getInstance().memSpec->iDD2N2; + memPowerSpec.idd3p0 = Configuration::getInstance().memSpec->iDD3P0; + memPowerSpec.idd3p02 = Configuration::getInstance().memSpec->iDD3P02; + memPowerSpec.idd3p1 = Configuration::getInstance().memSpec->iDD3P1; + memPowerSpec.idd3p12 = Configuration::getInstance().memSpec->iDD3P12; + memPowerSpec.idd3n = Configuration::getInstance().memSpec->iDD3N; + memPowerSpec.idd3n2 = Configuration::getInstance().memSpec->iDD3N2; + memPowerSpec.idd4r = Configuration::getInstance().memSpec->iDD4R; + memPowerSpec.idd4r2 = Configuration::getInstance().memSpec->iDD4R2; + memPowerSpec.idd4w = Configuration::getInstance().memSpec->iDD4W; + memPowerSpec.idd4w2 = Configuration::getInstance().memSpec->iDD4W2; + memPowerSpec.idd5 = Configuration::getInstance().memSpec->iDD5; + memPowerSpec.idd52 = Configuration::getInstance().memSpec->iDD52; + memPowerSpec.idd6 = Configuration::getInstance().memSpec->iDD6; + memPowerSpec.idd62 = Configuration::getInstance().memSpec->iDD62; + memPowerSpec.vdd = Configuration::getInstance().memSpec->vDD; + memPowerSpec.vdd2 = Configuration::getInstance().memSpec->vDD2; - MemorySpecification memSpec; - memSpec.id = Configuration::getInstance().memSpec->MemoryId; - memSpec.memoryType = Configuration::getInstance().memSpec->MemoryType; - memSpec.memTimingSpec = memTimingSpec; - memSpec.memPowerSpec = memPowerSpec; - memSpec.memArchSpec = memArchSpec; + MemorySpecification memSpec; + memSpec.id = Configuration::getInstance().memSpec->MemoryId; + memSpec.memoryType = Configuration::getInstance().memSpec->MemoryType; + memSpec.memTimingSpec = memTimingSpec; + memSpec.memPowerSpec = memPowerSpec; + memSpec.memArchSpec = memArchSpec; - DRAMPower = new libDRAMPower(memSpec, 0); - } - - // For each bank in a channel a error Model is created: - if (StoreMode == StorageMode::ErrorModel) - { - for (unsigned i = 0; i < Configuration::getInstance().memSpec->NumberOfBanks; - i++) - { - errorModel *em; - std::string errorModelStr = "errorModel_bank" + std::to_string(i); - if (powerAnalysis) - em = new errorModel(errorModelStr.c_str(), DRAMPower); - else - em = new errorModel(errorModelStr.c_str()); - ememory.push_back(em); - } - } + DRAMPower = new libDRAMPower(memSpec, 0); } Dram::~Dram() { - if (powerAnalysis) - { - if (!Configuration::getInstance().DatabaseRecording) - DRAMPower->calcEnergy(); + if (!Configuration::getInstance().DatabaseRecording) + DRAMPower->calcEnergy(); - // Print the final total energy and the average power for - // the simulation: - cout << name() << string(" Total Energy: ") - << fixed << std::setprecision( 2 ) - << DRAMPower->getEnergy().total_energy - * Configuration::getInstance().NumberOfDevicesOnDIMM - << string(" pJ") - << endl; + // Print the final total energy and the average power for + // the simulation: + cout << name() << string(" Total Energy: ") + << fixed << std::setprecision( 2 ) + << DRAMPower->getEnergy().total_energy + * Configuration::getInstance().NumberOfDevicesOnDIMM + << string(" pJ") + << endl; - cout << name() << string(" Average Power: ") - << fixed << std::setprecision( 2 ) - << DRAMPower->getPower().average_power - * Configuration::getInstance().NumberOfDevicesOnDIMM - << string(" mW") << endl; - } - - // Clean up: - for (auto e : ememory) - delete e; + cout << name() << string(" Average Power: ") + << fixed << std::setprecision( 2 ) + << DRAMPower->getPower().average_power + * Configuration::getInstance().NumberOfDevicesOnDIMM + << string(" mW") << endl; if (Configuration::getInstance().UseMalloc) free(memory); @@ -247,232 +206,154 @@ tlm_sync_enum Dram::nb_transport_fw(tlm_generic_payload &payload, unsigned int bank = DramExtension::getExtension(payload).getBank().ID(); // This is only needed for power simulation: - unsigned long long cycle = 0; - if (powerAnalysis) - { - cycle = sc_time_stamp().value() / - Configuration::getInstance().memSpec->clk.value(); - } + unsigned long long cycle = sc_time_stamp().value() / + Configuration::getInstance().memSpec->clk.value(); if (phase == BEGIN_PREB) { - if (powerAnalysis) - DRAMPower->doCommand(MemCommand::PREB, bank, cycle); - + DRAMPower->doCommand(MemCommand::PREB, bank, cycle); sendToController(payload, END_PREB, delay + getExecutionTime(Command::PreB, payload)); } else if (phase == BEGIN_PRE) { - if (powerAnalysis) - DRAMPower->doCommand(MemCommand::PRE, bank, cycle); - + DRAMPower->doCommand(MemCommand::PRE, bank, cycle); sendToController(payload, END_PRE, delay + getExecutionTime(Command::Precharge, payload)); } else if (phase == BEGIN_PRE_ALL) { - if (powerAnalysis) - DRAMPower->doCommand(MemCommand::PREA, bank, cycle); - + DRAMPower->doCommand(MemCommand::PREA, bank, cycle); sendToController(payload, END_PRE_ALL, delay + getExecutionTime(Command::PrechargeAll, payload)); } else if (phase == BEGIN_ACTB) { - if (powerAnalysis) - DRAMPower->doCommand(MemCommand::ACTB, bank, cycle); - + DRAMPower->doCommand(MemCommand::ACTB, bank, cycle); sendToController(payload, END_ACTB, delay + getExecutionTime(Command::ActB, payload)); - unsigned int row = DramExtension::getExtension(payload).getRow().ID(); - if (StoreMode == StorageMode::ErrorModel) - ememory[bank]->activate(row); } else if (phase == BEGIN_ACT) { - if (powerAnalysis) - DRAMPower->doCommand(MemCommand::ACT, bank, cycle); - + DRAMPower->doCommand(MemCommand::ACT, bank, cycle); sendToController(payload, END_ACT, delay + getExecutionTime(Command::Activate, payload)); - unsigned int row = DramExtension::getExtension(payload).getRow().ID(); - - if (StoreMode == StorageMode::ErrorModel) - ememory[bank]->activate(row); } else if (phase == BEGIN_WR) { -#if !defined (DRAMSYS_PCT) && !defined (DRAMSYS_GEM5) - assert(payload.get_data_length() == bytesPerBurst); -#endif - - if (powerAnalysis) - DRAMPower->doCommand(MemCommand::WR, bank, cycle); - + DRAMPower->doCommand(MemCommand::WR, bank, cycle); // save data: - if (StoreMode == StorageMode::NoStorage) // Don't store data - {} - else if (StoreMode == StorageMode::Store) // Use Storage + if (StoreMode == StorageMode::Store) // Use Storage { unsigned char *phyAddr = memory + payload.get_address(); memcpy(phyAddr, payload.get_data_ptr(), payload.get_data_length()); } - else // if (StoreMode == StorageMode::ErrorModel) // Use Storage with Error Model - { - ememory[bank]->store(payload); - } sendToController(payload, END_WR, delay + getExecutionTime(Command::Write, payload)); } else if (phase == BEGIN_RD) { -#if !defined (DRAMSYS_PCT) && !defined (DRAMSYS_GEM5) - assert(payload.get_data_length() == bytesPerBurst); -#endif - - if (powerAnalysis) - DRAMPower->doCommand(MemCommand::RD, bank, cycle); - + DRAMPower->doCommand(MemCommand::RD, bank, cycle); // load data: if (StoreMode == StorageMode::Store) // use StorageMode { unsigned char *phyAddr = memory + payload.get_address(); memcpy(payload.get_data_ptr(), phyAddr, payload.get_data_length()); } - else if (StoreMode == StorageMode::ErrorModel) // use StorageMode with errormodel - { - ememory[bank]->load(payload); - } sendToController(payload, END_RD, delay + getExecutionTime(Command::Read, payload)); } else if (phase == BEGIN_WRA) { - if (powerAnalysis) - DRAMPower->doCommand(MemCommand::WRA, bank, cycle); - + DRAMPower->doCommand(MemCommand::WRA, bank, cycle); // save data: - if (StoreMode == StorageMode::NoStorage) // Don't store data - {} - else if (StoreMode == StorageMode::Store) // Use Storage + if (StoreMode == StorageMode::Store) // Use Storage { unsigned char *phyAddr = memory + payload.get_address(); memcpy(phyAddr, payload.get_data_ptr(), payload.get_data_length()); } - else // if (StoreMode == StorageMode::ErrorModel) // Use Storage with Error Model - { - ememory[bank]->store(payload); - } sendToController(payload, END_WRA, delay + getExecutionTime(Command::WriteA, payload)); } else if (phase == BEGIN_RDA) { - if (powerAnalysis) - DRAMPower->doCommand(MemCommand::RDA, bank, cycle); - + DRAMPower->doCommand(MemCommand::RDA, bank, cycle); // Load data: if (StoreMode == StorageMode::Store) // use StorageMode { unsigned char *phyAddr = memory + payload.get_address(); memcpy(payload.get_data_ptr(), phyAddr, payload.get_data_length()); } - else if (StoreMode == StorageMode::ErrorModel) // use StorageMode with errormodel - { - ememory[bank]->load(payload); - } sendToController(payload, END_RDA, delay + getExecutionTime(Command::ReadA, payload)); } else if (phase == BEGIN_REFA) { - if (powerAnalysis) - DRAMPower->doCommand(MemCommand::REF, bank, cycle); - + DRAMPower->doCommand(MemCommand::REF, bank, cycle); sendToController(payload, END_REFA, delay + getExecutionTime(Command::AutoRefresh, payload)); - unsigned int row = DramExtension::getExtension(payload).getRow().ID(); - - if (StoreMode == StorageMode::ErrorModel) - ememory[bank]->refresh(row); } else if (phase == BEGIN_REFB) { - if (powerAnalysis) - DRAMPower->doCommand(MemCommand::REFB, bank, cycle); - + DRAMPower->doCommand(MemCommand::REFB, bank, cycle); sendToController(payload, END_REFB, delay + getExecutionTime(Command::AutoRefresh, payload)); } // Powerdown phases have to be started and ended by the controller, because they do not have a fixed length else if (phase == BEGIN_PDNA) { - if (powerAnalysis) - DRAMPower->doCommand(MemCommand::PDN_S_ACT, bank, cycle); + DRAMPower->doCommand(MemCommand::PDN_S_ACT, bank, cycle); } else if (phase == END_PDNA) { - if (powerAnalysis) - DRAMPower->doCommand(MemCommand::PUP_ACT, bank, cycle); + DRAMPower->doCommand(MemCommand::PUP_ACT, bank, cycle); } else if (phase == BEGIN_PDNAB) { - if (powerAnalysis) - SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); + SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); } else if (phase == END_PDNAB) { - if (powerAnalysis) - SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); + SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); } else if (phase == BEGIN_PDNP) { - if (powerAnalysis) - DRAMPower->doCommand(MemCommand::PDN_S_PRE, bank, cycle); + DRAMPower->doCommand(MemCommand::PDN_S_PRE, bank, cycle); } else if (phase == END_PDNP) { - if (powerAnalysis) - DRAMPower->doCommand(MemCommand::PUP_PRE, bank, cycle); + DRAMPower->doCommand(MemCommand::PUP_PRE, bank, cycle); } else if (phase == BEGIN_PDNPB) { - if (powerAnalysis) - SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); + SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); } else if (phase == END_PDNPB) { - if (powerAnalysis) - SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); + SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); } else if (phase == BEGIN_SREF) { - if (powerAnalysis) - DRAMPower->doCommand(MemCommand::SREN, bank, cycle); + DRAMPower->doCommand(MemCommand::SREN, bank, cycle); } else if (phase == END_SREF) { - if (powerAnalysis) - DRAMPower->doCommand(MemCommand::SREX, bank, cycle); + DRAMPower->doCommand(MemCommand::SREX, bank, cycle); } else if (phase == BEGIN_SREFB) { - if (powerAnalysis) - SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); + SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); } else if (phase == END_SREFB) { - if (powerAnalysis) - SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); + SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); } else { - if (powerAnalysis) - SC_REPORT_FATAL("DRAM", "DRAM PEQ was called with unknown phase"); + SC_REPORT_FATAL("DRAM", "DRAM PEQ was called with unknown phase"); } - return tlm::TLM_ACCEPTED; + return TLM_ACCEPTED; } unsigned int Dram::transport_dbg(tlm_generic_payload &trans) diff --git a/DRAMSys/library/src/simulation/Dram.h b/DRAMSys/library/src/simulation/Dram.h index 2f4c15c2..372df02c 100644 --- a/DRAMSys/library/src/simulation/Dram.h +++ b/DRAMSys/library/src/simulation/Dram.h @@ -45,7 +45,7 @@ #include #include "../controller/Controller.h" #include "../controller/core/configuration/Configuration.h" -#include "../error/errormodel.h" +#include "../common/third_party/DRAMPower/src/libdrampower/LibDRAMPower.h" using namespace std; using namespace tlm; @@ -59,14 +59,11 @@ private: // Power Model related bool powerAnalysis = Configuration::getInstance().PowerAnalysis; - // Error Model related: - StorageMode StoreMode = Configuration::getInstance().StoreMode; - std::vector ememory; - +protected: // Data Storage: + StorageMode StoreMode = Configuration::getInstance().StoreMode; unsigned char *memory; -protected: libDRAMPower *DRAMPower; virtual tlm_sync_enum nb_transport_fw(tlm_generic_payload &payload, @@ -85,7 +82,7 @@ public: Dram(sc_module_name); SC_HAS_PROCESS(Dram); - ~Dram(); + virtual ~Dram(); }; #endif // DRAM_H diff --git a/DRAMSys/library/src/simulation/DramDDR3.cpp b/DRAMSys/library/src/simulation/DramDDR3.cpp index 91ba5736..ebe78c90 100644 --- a/DRAMSys/library/src/simulation/DramDDR3.cpp +++ b/DRAMSys/library/src/simulation/DramDDR3.cpp @@ -34,11 +34,12 @@ */ #include "DramDDR3.h" + #include "Dram.h" +#include "../controller/core/configuration/Configuration.h" DramDDR3::DramDDR3(sc_module_name name) : Dram(name) { - + if (StoreMode == StorageMode::ErrorModel) + SC_REPORT_FATAL("DramDDR3", "Error Model for DDR3 not supported"); } - -//DramDDR3::~DramDDR3() {} diff --git a/DRAMSys/library/src/simulation/DramDDR3.h b/DRAMSys/library/src/simulation/DramDDR3.h index 0bf0a8a9..0886d25a 100644 --- a/DRAMSys/library/src/simulation/DramDDR3.h +++ b/DRAMSys/library/src/simulation/DramDDR3.h @@ -45,8 +45,6 @@ class DramDDR3 : public Dram public: DramDDR3(sc_module_name); SC_HAS_PROCESS(DramDDR3); - - //~DramDDR3(); }; #endif // DRAMDDR3_H diff --git a/DRAMSys/library/src/simulation/DramDDR4.cpp b/DRAMSys/library/src/simulation/DramDDR4.cpp index b10cd313..8feeb259 100644 --- a/DRAMSys/library/src/simulation/DramDDR4.cpp +++ b/DRAMSys/library/src/simulation/DramDDR4.cpp @@ -34,11 +34,12 @@ */ #include "DramDDR4.h" + #include "Dram.h" +#include "../controller/core/configuration/Configuration.h" DramDDR4::DramDDR4(sc_module_name name) : Dram(name) { - + if (StoreMode == StorageMode::ErrorModel) + SC_REPORT_FATAL("DramDDR4", "Error Model for DDR4 not supported"); } - -//DramDDR4::~DramDDR4() {} diff --git a/DRAMSys/library/src/simulation/DramDDR4.h b/DRAMSys/library/src/simulation/DramDDR4.h index 64bae19d..5cf92424 100644 --- a/DRAMSys/library/src/simulation/DramDDR4.h +++ b/DRAMSys/library/src/simulation/DramDDR4.h @@ -40,15 +40,11 @@ #include #include -using namespace tlm; - class DramDDR4 : public Dram { public: DramDDR4(sc_module_name); SC_HAS_PROCESS(DramDDR4); - - //~DramDDR4(); }; #endif // DRAMDDR4_H diff --git a/DRAMSys/library/src/simulation/DramRecordable.cpp b/DRAMSys/library/src/simulation/DramRecordable.cpp index 56a3196a..cc24e5a2 100644 --- a/DRAMSys/library/src/simulation/DramRecordable.cpp +++ b/DRAMSys/library/src/simulation/DramRecordable.cpp @@ -39,6 +39,7 @@ #include "../common/TlmRecorder.h" #include "DramDDR3.h" #include "DramDDR4.h" +#include "DramWideIO.h" #include "../common/utils.h" using namespace tlm; @@ -138,4 +139,5 @@ void DramRecordable::recordPower() template class DramRecordable; template class DramRecordable; +template class DramRecordable; diff --git a/DRAMSys/library/src/simulation/DramRecordable.h b/DRAMSys/library/src/simulation/DramRecordable.h index 2e4231ff..59d6873a 100644 --- a/DRAMSys/library/src/simulation/DramRecordable.h +++ b/DRAMSys/library/src/simulation/DramRecordable.h @@ -52,7 +52,7 @@ public: DramRecordable(sc_module_name name, TlmRecorder *tlmRecorder); SC_HAS_PROCESS(DramRecordable); - ~DramRecordable(); + virtual ~DramRecordable(); protected: virtual tlm_sync_enum nb_transport_fw(tlm_generic_payload &payload, diff --git a/DRAMSys/library/src/simulation/DramWideIO.cpp b/DRAMSys/library/src/simulation/DramWideIO.cpp new file mode 100644 index 00000000..038d0671 --- /dev/null +++ b/DRAMSys/library/src/simulation/DramWideIO.cpp @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2019, University of Kaiserslautern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: + * Lukas Steiner + */ + +#include "DramWideIO.h" + +#include +#include +#include "Dram.h" + +using namespace tlm; + +DramWideIO::DramWideIO(sc_module_name name) : Dram(name) +{ + // For each bank in a channel a error Model is created: + if (StoreMode == StorageMode::ErrorModel) + { + if (Configuration::getInstance().UseMalloc) + free(memory); + + for (unsigned i = 0; i < Configuration::getInstance().memSpec->NumberOfBanks; + i++) + { + errorModel *em; + std::string errorModelStr = "errorModel_bank" + std::to_string(i); + em = new errorModel(errorModelStr.c_str(), DRAMPower); + ememory.push_back(em); + } + } +} + +DramWideIO::~DramWideIO() +{ + // Clean up: + for (auto e : ememory) + delete e; +} + +tlm_sync_enum DramWideIO::nb_transport_fw(tlm_generic_payload &payload, + tlm_phase &phase, sc_time &delay) +{ + unsigned int bank = DramExtension::getExtension(payload).getBank().ID(); + + // This is only needed for power simulation: + unsigned long long cycle = sc_time_stamp().value() / + Configuration::getInstance().memSpec->clk.value(); + + if (phase == BEGIN_PREB) + { + DRAMPower->doCommand(MemCommand::PREB, bank, cycle); + sendToController(payload, END_PREB, delay + getExecutionTime(Command::PreB, + payload)); + } + else if (phase == BEGIN_PRE) + { + DRAMPower->doCommand(MemCommand::PRE, bank, cycle); + sendToController(payload, END_PRE, delay + getExecutionTime(Command::Precharge, + payload)); + } + else if (phase == BEGIN_PRE_ALL) + { + DRAMPower->doCommand(MemCommand::PREA, bank, cycle); + sendToController(payload, END_PRE_ALL, + delay + getExecutionTime(Command::PrechargeAll, payload)); + } + else if (phase == BEGIN_ACTB) + { + DRAMPower->doCommand(MemCommand::ACTB, bank, cycle); + sendToController(payload, END_ACTB, delay + getExecutionTime(Command::ActB, + payload)); + unsigned int row = DramExtension::getExtension(payload).getRow().ID(); + if (StoreMode == StorageMode::ErrorModel) + ememory[bank]->activate(row); + } + else if (phase == BEGIN_ACT) + { + DRAMPower->doCommand(MemCommand::ACT, bank, cycle); + sendToController(payload, END_ACT, delay + getExecutionTime(Command::Activate, + payload)); + unsigned int row = DramExtension::getExtension(payload).getRow().ID(); + + if (StoreMode == StorageMode::ErrorModel) + ememory[bank]->activate(row); + } + else if (phase == BEGIN_WR) + { + DRAMPower->doCommand(MemCommand::WR, bank, cycle); + // save data: + if (StoreMode == StorageMode::Store) // Use Storage + { + unsigned char *phyAddr = memory + payload.get_address(); + memcpy(phyAddr, payload.get_data_ptr(), payload.get_data_length()); + } + else if (StoreMode == StorageMode::ErrorModel) // Use Storage with Error Model + { + ememory[bank]->store(payload); + } + sendToController(payload, END_WR, delay + getExecutionTime(Command::Write, + payload)); + } + else if (phase == BEGIN_RD) + { + DRAMPower->doCommand(MemCommand::RD, bank, cycle); + // load data: + if (StoreMode == StorageMode::Store) // use StorageMode + { + unsigned char *phyAddr = memory + payload.get_address(); + memcpy(payload.get_data_ptr(), phyAddr, payload.get_data_length()); + } + else if (StoreMode == StorageMode::ErrorModel) // use StorageMode with errormodel + { + ememory[bank]->load(payload); + } + sendToController(payload, END_RD, delay + getExecutionTime(Command::Read, + payload)); + } + else if (phase == BEGIN_WRA) + { + DRAMPower->doCommand(MemCommand::WRA, bank, cycle); + // save data: + if (StoreMode == StorageMode::Store) // Use Storage + { + unsigned char *phyAddr = memory + payload.get_address(); + memcpy(phyAddr, payload.get_data_ptr(), payload.get_data_length()); + } + else if (StoreMode == StorageMode::ErrorModel) // Use Storage with Error Model + { + ememory[bank]->store(payload); + } + sendToController(payload, END_WRA, delay + getExecutionTime(Command::WriteA, + payload)); + } + else if (phase == BEGIN_RDA) + { + DRAMPower->doCommand(MemCommand::RDA, bank, cycle); + // Load data: + if (StoreMode == StorageMode::Store) // use StorageMode + { + unsigned char *phyAddr = memory + payload.get_address(); + memcpy(payload.get_data_ptr(), phyAddr, payload.get_data_length()); + } + else if (StoreMode == StorageMode::ErrorModel) // use StorageMode with errormodel + { + ememory[bank]->load(payload); + } + sendToController(payload, END_RDA, delay + getExecutionTime(Command::ReadA, + payload)); + } + else if (phase == BEGIN_REFA) + { + DRAMPower->doCommand(MemCommand::REF, bank, cycle); + sendToController(payload, END_REFA, + delay + getExecutionTime(Command::AutoRefresh, payload)); + unsigned int row = DramExtension::getExtension(payload).getRow().ID(); + + if (StoreMode == StorageMode::ErrorModel) + ememory[bank]->refresh(row); + } + else if (phase == BEGIN_REFB) + { + DRAMPower->doCommand(MemCommand::REFB, bank, cycle); + sendToController(payload, END_REFB, + delay + getExecutionTime(Command::AutoRefresh, payload)); + } + // Powerdown phases have to be started and ended by the controller, because they do not have a fixed length + else if (phase == BEGIN_PDNA) + { + DRAMPower->doCommand(MemCommand::PDN_S_ACT, bank, cycle); + } + else if (phase == END_PDNA) + { + DRAMPower->doCommand(MemCommand::PUP_ACT, bank, cycle); + } + else if (phase == BEGIN_PDNAB) + { + SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); + } + else if (phase == END_PDNAB) + { + SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); + } + else if (phase == BEGIN_PDNP) + { + DRAMPower->doCommand(MemCommand::PDN_S_PRE, bank, cycle); + } + else if (phase == END_PDNP) + { + DRAMPower->doCommand(MemCommand::PUP_PRE, bank, cycle); + } + else if (phase == BEGIN_PDNPB) + { + SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); + } + else if (phase == END_PDNPB) + { + SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); + } + else if (phase == BEGIN_SREF) + { + DRAMPower->doCommand(MemCommand::SREN, bank, cycle); + } + else if (phase == END_SREF) + { + DRAMPower->doCommand(MemCommand::SREX, bank, cycle); + } + else if (phase == BEGIN_SREFB) + { + SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); + } + else if (phase == END_SREFB) + { + SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported"); + } + else + { + SC_REPORT_FATAL("DRAM", "DRAM PEQ was called with unknown phase"); + } + + return TLM_ACCEPTED; +} diff --git a/DRAMSys/library/src/simulation/DramWideIO.h b/DRAMSys/library/src/simulation/DramWideIO.h new file mode 100644 index 00000000..56e0b39a --- /dev/null +++ b/DRAMSys/library/src/simulation/DramWideIO.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019, University of Kaiserslautern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: + * Lukas Steiner + */ + +#ifndef DRAMWIDEIO_H +#define DRAMWIDEIO_H + +#include +#include +#include "Dram.h" +#include "../error/errormodel.h" + +using namespace tlm; + +class DramWideIO : public Dram +{ +public: + DramWideIO(sc_module_name); + SC_HAS_PROCESS(DramWideIO); + + virtual ~DramWideIO(); + +protected: + virtual tlm_sync_enum nb_transport_fw(tlm_generic_payload &payload, + tlm_phase &phase, sc_time &delay); + +private: + std::vector ememory; +}; + +#endif // DRAMWIDEIO_H From d07a775697feefe5cb2c958a06803e0bd0cdead3 Mon Sep 17 00:00:00 2001 From: "Lukas Steiner (2)" Date: Mon, 24 Jun 2019 13:59:57 +0200 Subject: [PATCH 96/97] Annotations for different MemSpecs. --- .../configuration/ConfigurationLoader.cpp | 134 +++++++++--------- DRAMSys/library/src/simulation/Dram.cpp | 1 - DRAMSys/library/src/simulation/DramWideIO.cpp | 2 + 3 files changed, 69 insertions(+), 68 deletions(-) diff --git a/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.cpp b/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.cpp index def1d129..a4d3f94f 100644 --- a/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.cpp +++ b/DRAMSys/library/src/controller/core/configuration/ConfigurationLoader.cpp @@ -177,17 +177,17 @@ void ConfigurationLoader::loadDDR3(Configuration &config, XMLElement *memspec) XMLElement *architecture = memspec->FirstChildElement("memarchitecturespec"); config.memSpec->NumberOfBanks = queryUIntParameter(architecture, "nbrOfBanks"); - config.memSpec->NumberOfBankGroups = 1; + config.memSpec->NumberOfBankGroups = 1; config.memSpec->NumberOfRanks = queryUIntParameter(architecture, "nbrOfRanks"); config.memSpec->BurstLength = queryUIntParameter(architecture, "burstLength"); - config.memSpec->nActivate = 4; + config.memSpec->nActivate = 4; config.memSpec->DataRate = queryUIntParameter(architecture, "dataRate"); config.memSpec->NumberOfRows = queryUIntParameter(architecture, "nbrOfRows"); config.memSpec->NumberOfColumns = queryUIntParameter(architecture, "nbrOfColumns"); config.memSpec->bitWidth = queryUIntParameter(architecture, "width"); - config.memSpec->DLL = true; - config.memSpec->termination = true; + config.memSpec->DLL = true; + config.memSpec->termination = true; //MemTimings XMLElement *timings = memspec->FirstChildElement("memtimingspec"); @@ -198,29 +198,29 @@ void ConfigurationLoader::loadDDR3(Configuration &config, XMLElement *memspec) config.memSpec->tRAS = clk * queryUIntParameter(timings, "RAS"); config.memSpec->tRC = clk * queryUIntParameter(timings, "RC"); config.memSpec->tRTP = clk * queryUIntParameter(timings, "RTP"); - config.memSpec->tRRD_S = clk * queryUIntParameter(timings, "RRD"); - config.memSpec->tRRD_L = clk * queryUIntParameter(timings, "RRD"); - config.memSpec->tCCD_S = clk * queryUIntParameter(timings, "CCD"); - config.memSpec->tCCD_L = clk * queryUIntParameter(timings, "CCD"); + config.memSpec->tRRD_S = clk * queryUIntParameter(timings, "RRD"); + config.memSpec->tRRD_L = clk * queryUIntParameter(timings, "RRD"); + config.memSpec->tCCD_S = clk * queryUIntParameter(timings, "CCD"); + config.memSpec->tCCD_L = clk * queryUIntParameter(timings, "CCD"); config.memSpec->tRCD = clk * queryUIntParameter(timings, "RCD"); - config.memSpec->tNAW = clk * queryUIntParameter(timings, "FAW"); + config.memSpec->tNAW = clk * queryUIntParameter(timings, "FAW"); config.memSpec->tRL = clk * queryUIntParameter(timings, "RL"); config.memSpec->tWL = clk * queryUIntParameter(timings, "WL"); config.memSpec->tWR = clk * queryUIntParameter(timings, "WR"); - config.memSpec->tWTR_S = clk * queryUIntParameter(timings, "WTR"); - config.memSpec->tWTR_L = clk * queryUIntParameter(timings, "WTR"); + config.memSpec->tWTR_S = clk * queryUIntParameter(timings, "WTR"); + config.memSpec->tWTR_L = clk * queryUIntParameter(timings, "WTR"); config.memSpec->tCKESR = clk * queryUIntParameter(timings, "CKESR"); config.memSpec->tCKE = clk * queryUIntParameter(timings, "CKE"); config.memSpec->tXP = clk * queryUIntParameter(timings, "XP"); config.memSpec->tXPDLL = clk * queryUIntParameter(timings, "XPDLL"); - config.memSpec->tXSR = clk * queryUIntParameter(timings, "XS"); - config.memSpec->tXSRDLL = clk * queryUIntParameter(timings, "XSDLL"); + config.memSpec->tXSR = clk * queryUIntParameter(timings, "XS"); + config.memSpec->tXSRDLL = clk * queryUIntParameter(timings, "XSDLL"); config.memSpec->tAL = clk * queryUIntParameter(timings, "AL"); config.memSpec->tRFC = clk * queryUIntParameter(timings, "RFC"); config.memSpec->tREFI = clk * queryUIntParameter(timings, "REFI"); config.memSpec->tDQSCK = clk * queryUIntParameter(timings, "DQSCK"); - config.memSpec->refreshTimings.clear(); + config.memSpec->refreshTimings.clear(); for (unsigned int i = 0; i < config.memSpec->NumberOfBanks; ++i) { config.memSpec->refreshTimings[Bank(i)] = RefreshTiming(config.memSpec->tRFC, config.memSpec->tREFI); @@ -229,7 +229,7 @@ void ConfigurationLoader::loadDDR3(Configuration &config, XMLElement *memspec) // Currents and Volatages: TODO Check if this is correct. XMLElement *powers = memspec->FirstChildElement("mempowerspec"); config.memSpec->iDD0 = queryDoubleParameter(powers, "idd0"); - config.memSpec->iDD02 = 0; + config.memSpec->iDD02 = 0; config.memSpec->iDD2P0 = queryDoubleParameter(powers, "idd2p0"); config.memSpec->iDD2P1 = queryDoubleParameter(powers, "idd2p1"); config.memSpec->iDD2N = queryDoubleParameter(powers, "idd2n"); @@ -240,9 +240,9 @@ void ConfigurationLoader::loadDDR3(Configuration &config, XMLElement *memspec) config.memSpec->iDD4W = queryDoubleParameter(powers, "idd4w"); config.memSpec->iDD5 = queryDoubleParameter(powers, "idd5"); config.memSpec->iDD6 = queryDoubleParameter(powers, "idd6"); - config.memSpec->iDD62 = 0; + config.memSpec->iDD62 = 0; config.memSpec->vDD = queryDoubleParameter(powers, "vdd"); - config.memSpec->vDD2 = 0; + config.memSpec->vDD2 = 0; } void ConfigurationLoader::loadDDR4(Configuration &config, XMLElement *memspec) @@ -255,14 +255,14 @@ void ConfigurationLoader::loadDDR4(Configuration &config, XMLElement *memspec) "nbrOfBankGroups"); config.memSpec->NumberOfRanks = queryUIntParameter(architecture, "nbrOfRanks"); config.memSpec->BurstLength = queryUIntParameter(architecture, "burstLength"); - config.memSpec->nActivate = 4; + config.memSpec->nActivate = 4; config.memSpec->DataRate = queryUIntParameter(architecture, "dataRate"); config.memSpec->NumberOfRows = queryUIntParameter(architecture, "nbrOfRows"); config.memSpec->NumberOfColumns = queryUIntParameter(architecture, "nbrOfColumns"); config.memSpec->bitWidth = queryUIntParameter(architecture, "width"); - config.memSpec->DLL = true; - config.memSpec->termination = true; + config.memSpec->DLL = true; + config.memSpec->termination = true; //MemTimings XMLElement *timings = memspec->FirstChildElement("memtimingspec"); @@ -278,7 +278,7 @@ void ConfigurationLoader::loadDDR4(Configuration &config, XMLElement *memspec) config.memSpec->tCCD_S = clk * queryUIntParameter(timings, "CCD_S"); config.memSpec->tCCD_L = clk * queryUIntParameter(timings, "CCD_L"); config.memSpec->tRCD = clk * queryUIntParameter(timings, "RCD"); - config.memSpec->tNAW = clk * queryUIntParameter(timings, "FAW"); + config.memSpec->tNAW = clk * queryUIntParameter(timings, "FAW"); config.memSpec->tRL = clk * queryUIntParameter(timings, "RL"); config.memSpec->tWL = clk * queryUIntParameter(timings, "WL"); config.memSpec->tWR = clk * queryUIntParameter(timings, "WR"); @@ -288,8 +288,8 @@ void ConfigurationLoader::loadDDR4(Configuration &config, XMLElement *memspec) config.memSpec->tCKE = clk * queryUIntParameter(timings, "CKE"); config.memSpec->tXP = clk * queryUIntParameter(timings, "XP"); config.memSpec->tXPDLL = clk * queryUIntParameter(timings, "XPDLL"); - config.memSpec->tXSR = clk * queryUIntParameter(timings, "XS"); - config.memSpec->tXSRDLL = clk * queryUIntParameter(timings, "XSDLL"); + config.memSpec->tXSR = clk * queryUIntParameter(timings, "XS"); + config.memSpec->tXSRDLL = clk * queryUIntParameter(timings, "XSDLL"); config.memSpec->tAL = clk * queryUIntParameter(timings, "AL"); config.memSpec->tRFC = clk * queryUIntParameter(timings, "RFC"); config.memSpec->tRFC2 = clk * queryUIntParameter(timings, "RFC2"); @@ -324,60 +324,60 @@ void ConfigurationLoader::loadDDR4(Configuration &config, XMLElement *memspec) config.memSpec->vDD2 = queryDoubleParameter(powers, "vdd2"); } -// TODO: fix this for LPDDR4 +// TODO: change timings for LPDDR4 void ConfigurationLoader::loadLPDDR4(Configuration &config, XMLElement *memspec) { //MemArchitecture: XMLElement *architecture = memspec->FirstChildElement("memarchitecturespec"); config.memSpec->NumberOfBanks = queryUIntParameter(architecture, "nbrOfBanks"); - config.memSpec->NumberOfBankGroups = 1; + config.memSpec->NumberOfBankGroups = 1; config.memSpec->NumberOfRanks = queryUIntParameter(architecture, "nbrOfRanks"); config.memSpec->BurstLength = queryUIntParameter(architecture, "burstLength"); - config.memSpec->nActivate = 4; + config.memSpec->nActivate = 4; config.memSpec->DataRate = queryUIntParameter(architecture, "dataRate"); config.memSpec->NumberOfRows = queryUIntParameter(architecture, "nbrOfRows"); config.memSpec->NumberOfColumns = queryUIntParameter(architecture, "nbrOfColumns"); config.memSpec->bitWidth = queryUIntParameter(architecture, "width"); - config.memSpec->DLL = false; // TODO: Correct? - config.memSpec->termination = true; // TODO: Correct? + config.memSpec->DLL = false; // TODO: Correct? + config.memSpec->termination = true; // TODO: Correct? //MemTimings XMLElement *timings = memspec->FirstChildElement("memtimingspec"); config.memSpec->clkMHz = queryDoubleParameter(timings, "clkMhz"); config.memSpec->clk = FrequencyToClk(config.memSpec->clkMHz); sc_time clk = config.memSpec->clk; - config.memSpec->tRP = clk * queryUIntParameter(timings, "RPPB"); + config.memSpec->tRP = clk * queryUIntParameter(timings, "RPPB"); config.memSpec->tRPAB = clk * queryUIntParameter(timings, "RPAB"); config.memSpec->tRAS = clk * queryUIntParameter(timings, "RAS"); config.memSpec->tRC = clk * queryUIntParameter(timings, "RC"); config.memSpec->tRTP = clk * queryUIntParameter(timings, "RTP"); - config.memSpec->tRRD_S = clk * queryUIntParameter(timings, "RRD"); - config.memSpec->tRRD_L = clk * queryUIntParameter(timings, "RRD"); - config.memSpec->tCCD_S = clk * queryUIntParameter(timings, "CCD"); - config.memSpec->tCCD_L = clk * queryUIntParameter(timings, "CCD"); + config.memSpec->tRRD_S = clk * queryUIntParameter(timings, "RRD"); + config.memSpec->tRRD_L = clk * queryUIntParameter(timings, "RRD"); + config.memSpec->tCCD_S = clk * queryUIntParameter(timings, "CCD"); + config.memSpec->tCCD_L = clk * queryUIntParameter(timings, "CCD"); config.memSpec->tRCD = clk * queryUIntParameter(timings, "RCD"); - config.memSpec->tNAW = clk * queryUIntParameter(timings, "FAW"); + config.memSpec->tNAW = clk * queryUIntParameter(timings, "FAW"); config.memSpec->tRL = clk * queryUIntParameter(timings, "RL"); config.memSpec->tWL = clk * queryUIntParameter(timings, "WL"); config.memSpec->tWR = clk * queryUIntParameter(timings, "WR"); - config.memSpec->tWTR_S = clk * queryUIntParameter(timings, "WTR"); - config.memSpec->tWTR_L = clk * queryUIntParameter(timings, "WTR"); + config.memSpec->tWTR_S = clk * queryUIntParameter(timings, "WTR"); + config.memSpec->tWTR_L = clk * queryUIntParameter(timings, "WTR"); config.memSpec->tCKESR = clk * queryUIntParameter(timings, "CKESR"); config.memSpec->tCKE = clk * queryUIntParameter(timings, "CKE"); config.memSpec->tXP = clk * queryUIntParameter(timings, "XP"); - config.memSpec->tXPDLL = clk * queryUIntParameter(timings, "XP"); - config.memSpec->tXSR = clk * queryUIntParameter(timings, "XS"); - config.memSpec->tXSRDLL = clk * queryUIntParameter(timings, "XS"); + config.memSpec->tXPDLL = clk * queryUIntParameter(timings, "XP"); + config.memSpec->tXSR = clk * queryUIntParameter(timings, "XS"); + config.memSpec->tXSRDLL = clk * queryUIntParameter(timings, "XS"); config.memSpec->tAL = clk * queryUIntParameter(timings, "AL"); - config.memSpec->tRFC = clk * queryUIntParameter(timings, "RFCAB"); - // TODO: config.memSpec->tRFCPB = clk * queryUIntParameter(timings, "RFCPB"); - config.memSpec->tREFI = clk * queryUIntParameter(timings, "REFIAB"); - // TODO: config.memSpec->tREFIPB = clk * queryUIntParameter(timings, "RFCPB"); + config.memSpec->tRFC = clk * queryUIntParameter(timings, "RFCAB"); + // TODO: config.memSpec->tRFCPB = clk * queryUIntParameter(timings, "RFCPB"); + config.memSpec->tREFI = clk * queryUIntParameter(timings, "REFIAB"); + // TODO: config.memSpec->tREFIPB = clk * queryUIntParameter(timings, "RFCPB"); config.memSpec->tDQSCK = clk * queryUIntParameter(timings, "DQSCK"); - config.memSpec->refreshTimings.clear(); + config.memSpec->refreshTimings.clear(); for (unsigned int i = 0; i < config.memSpec->NumberOfBanks; ++i) { config.memSpec->refreshTimings[Bank(i)] = RefreshTiming(config.memSpec->tRFC, config.memSpec->tREFI); @@ -387,11 +387,11 @@ void ConfigurationLoader::loadLPDDR4(Configuration &config, XMLElement *memspec) XMLElement *powers = memspec->FirstChildElement("mempowerspec"); config.memSpec->iDD0 = queryDoubleParameter(powers, "idd0"); config.memSpec->iDD02 = queryDoubleParameter(powers, "idd02"); - config.memSpec->iDD2P0 = queryDoubleParameter(powers, "idd2p"); - config.memSpec->iDD2P1 = queryDoubleParameter(powers, "idd2p2"); + config.memSpec->iDD2P0 = queryDoubleParameter(powers, "idd2p"); + config.memSpec->iDD2P1 = queryDoubleParameter(powers, "idd2p2"); config.memSpec->iDD2N = queryDoubleParameter(powers, "idd2n"); - config.memSpec->iDD3P0 = queryDoubleParameter(powers, "idd3p"); - config.memSpec->iDD3P1 = queryDoubleParameter(powers, "idd3p2"); + config.memSpec->iDD3P0 = queryDoubleParameter(powers, "idd3p"); + config.memSpec->iDD3P1 = queryDoubleParameter(powers, "idd3p2"); config.memSpec->iDD3N = queryDoubleParameter(powers, "idd3n"); config.memSpec->iDD4R = queryDoubleParameter(powers, "idd4r"); config.memSpec->iDD4W = queryDoubleParameter(powers, "idd4w"); @@ -408,17 +408,17 @@ void ConfigurationLoader::loadWideIO(Configuration &config, XMLElement *memspec) XMLElement *architecture = memspec->FirstChildElement("memarchitecturespec"); config.memSpec->NumberOfBanks = queryUIntParameter(architecture, "nbrOfBanks"); - config.memSpec->NumberOfBankGroups = 1; - config.memSpec->NumberOfRanks = 1; + config.memSpec->NumberOfBankGroups = 1; + config.memSpec->NumberOfRanks = 1; config.memSpec->BurstLength = queryUIntParameter(architecture, "burstLength"); - config.memSpec->nActivate = 2; + config.memSpec->nActivate = 2; config.memSpec->DataRate = queryUIntParameter(architecture, "dataRate"); config.memSpec->NumberOfRows = queryUIntParameter(architecture, "nbrOfRows"); config.memSpec->NumberOfColumns = queryUIntParameter(architecture, "nbrOfColumns"); config.memSpec->bitWidth = queryUIntParameter(architecture, "width"); - config.memSpec->DLL = false; - config.memSpec->termination = false; + config.memSpec->DLL = false; + config.memSpec->termination = false; //MemTimings XMLElement *timings = memspec->FirstChildElement("memtimingspec"); @@ -428,29 +428,29 @@ void ConfigurationLoader::loadWideIO(Configuration &config, XMLElement *memspec) config.memSpec->tRP = clk * queryUIntParameter(timings, "RP"); config.memSpec->tRAS = clk * queryUIntParameter(timings, "RAS"); config.memSpec->tRC = clk * queryUIntParameter(timings, "RC"); - config.memSpec->tRRD_S = clk * queryUIntParameter(timings, "RRD"); - config.memSpec->tRRD_L = config.memSpec->tRRD_S; - config.memSpec->tCCD_S = clk * queryUIntParameter(timings, "CCD"); - config.memSpec->tCCD_L = config.memSpec->tCCD_S; + config.memSpec->tRRD_S = clk * queryUIntParameter(timings, "RRD"); + config.memSpec->tRRD_L = config.memSpec->tRRD_S; + config.memSpec->tCCD_S = clk * queryUIntParameter(timings, "CCD"); + config.memSpec->tCCD_L = config.memSpec->tCCD_S; config.memSpec->tRCD = clk * queryUIntParameter(timings, "RCD"); - config.memSpec->tNAW = clk * queryUIntParameter(timings, "TAW"); + config.memSpec->tNAW = clk * queryUIntParameter(timings, "TAW"); config.memSpec->tRL = clk * queryUIntParameter(timings, "RL"); config.memSpec->tWL = clk * queryUIntParameter(timings, "WL"); config.memSpec->tWR = clk * queryUIntParameter(timings, "WR"); - config.memSpec->tWTR_S = clk * queryUIntParameter(timings, "WTR"); - config.memSpec->tWTR_L = config.memSpec->tWTR_S; + config.memSpec->tWTR_S = clk * queryUIntParameter(timings, "WTR"); + config.memSpec->tWTR_L = config.memSpec->tWTR_S; config.memSpec->tRTP = clk * queryUIntParameter(timings, "RTP"); config.memSpec->tCKESR = clk * queryUIntParameter(timings, "CKESR"); config.memSpec->tCKE = clk * queryUIntParameter(timings, "CKE"); config.memSpec->tXP = clk * queryUIntParameter(timings, "XP"); - config.memSpec->tXPDLL = config.memSpec->tXP; - config.memSpec->tXSR = clk * queryUIntParameter(timings, "XS"); - config.memSpec->tXSRDLL = config.memSpec->tXSR; - config.memSpec->tAL = clk * queryUIntParameter(timings, "AL"); - config.memSpec->tRFC = clk * queryUIntParameter(timings, "RFC"); - config.memSpec->tREFI = clk * queryUIntParameter(timings, "REFI"); + config.memSpec->tXPDLL = config.memSpec->tXP; + config.memSpec->tXSR = clk * queryUIntParameter(timings, "XS"); + config.memSpec->tXSRDLL = config.memSpec->tXSR; + config.memSpec->tAL = clk * queryUIntParameter(timings, "AL"); + config.memSpec->tRFC = clk * queryUIntParameter(timings, "RFC"); + config.memSpec->tREFI = clk * queryUIntParameter(timings, "REFI"); - config.memSpec->refreshTimings.clear(); + config.memSpec->refreshTimings.clear(); for (unsigned int i = 0; i < config.memSpec->NumberOfBanks; ++i) { config.memSpec->refreshTimings[Bank(i)] = RefreshTiming(config.memSpec->tRFC, config.memSpec->tREFI); diff --git a/DRAMSys/library/src/simulation/Dram.cpp b/DRAMSys/library/src/simulation/Dram.cpp index af3a1594..cc391efc 100644 --- a/DRAMSys/library/src/simulation/Dram.cpp +++ b/DRAMSys/library/src/simulation/Dram.cpp @@ -56,7 +56,6 @@ #include "../common/protocol.h" #include "../common/utils.h" #include "../common/third_party/DRAMPower/src/libdrampower/LibDRAMPower.h" -#include "../error/errormodel.h" using namespace std; using namespace tlm; diff --git a/DRAMSys/library/src/simulation/DramWideIO.cpp b/DRAMSys/library/src/simulation/DramWideIO.cpp index 038d0671..3f69ca7a 100644 --- a/DRAMSys/library/src/simulation/DramWideIO.cpp +++ b/DRAMSys/library/src/simulation/DramWideIO.cpp @@ -38,6 +38,8 @@ #include #include #include "Dram.h" +#include "../controller/core/configuration/Configuration.h" +#include "../error/errormodel.h" using namespace tlm; From a303f242e656812a1882c56d88c551fad07bf565 Mon Sep 17 00:00:00 2001 From: "Lukas Steiner (2)" Date: Thu, 25 Jul 2019 11:49:18 +0200 Subject: [PATCH 97/97] Included googletest and subproject for unit tests. --- .gitmodules | 3 ++ DRAMSys/DRAMSys.pro | 2 + DRAMSys/unitTests/Testfile.h | 7 +++ DRAMSys/unitTests/googleTest.pri | 23 ++++++++++ DRAMSys/unitTests/googletest | 1 + DRAMSys/unitTests/main.cpp | 9 ++++ DRAMSys/unitTests/unitTests.pro | 77 ++++++++++++++++++++++++++++++++ 7 files changed, 122 insertions(+) create mode 100644 DRAMSys/unitTests/Testfile.h create mode 100644 DRAMSys/unitTests/googleTest.pri create mode 160000 DRAMSys/unitTests/googletest create mode 100644 DRAMSys/unitTests/main.cpp create mode 100644 DRAMSys/unitTests/unitTests.pro diff --git a/.gitmodules b/.gitmodules index 82647b71..458b70e3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,3 +5,6 @@ path = DRAMSys/library/src/common/third_party/DRAMPower url = https://github.com/tukl-msd/DRAMPower.git branch = master +[submodule "DRAMSys/unitTests/googletest"] + path = DRAMSys/unitTests/googletest + url = https://github.com/google/googletest.git diff --git a/DRAMSys/DRAMSys.pro b/DRAMSys/DRAMSys.pro index 83be2a95..d4a5e29e 100644 --- a/DRAMSys/DRAMSys.pro +++ b/DRAMSys/DRAMSys.pro @@ -25,10 +25,12 @@ isEmpty(systemc_home) { message(SystemC home is $${systemc_home}) SUBDIRS += library +SUBDIRS += unitTests SUBDIRS += simulator SUBDIRS += traceAnalyzer library.subdir = library +unitTests.subdir = unitTests simulator.subdir = simulator traceAnalyzer.subdir = traceAnalyzer diff --git a/DRAMSys/unitTests/Testfile.h b/DRAMSys/unitTests/Testfile.h new file mode 100644 index 00000000..50726e5c --- /dev/null +++ b/DRAMSys/unitTests/Testfile.h @@ -0,0 +1,7 @@ +#include +#include "../library/src/controller/Command.h" + +TEST(testsuite, test) +{ + EXPECT_EQ(commandToString(Command::Activate), "ACT"); +} diff --git a/DRAMSys/unitTests/googleTest.pri b/DRAMSys/unitTests/googleTest.pri new file mode 100644 index 00000000..122881e3 --- /dev/null +++ b/DRAMSys/unitTests/googleTest.pri @@ -0,0 +1,23 @@ +GOOGLETEST_DIR = googletest + +!isEmpty(GOOGLETEST_DIR): { + GTEST_SRCDIR = $$GOOGLETEST_DIR/googletest + GMOCK_SRCDIR = $$GOOGLETEST_DIR/googlemock +} + +requires(exists($$GTEST_SRCDIR):exists($$GMOCK_SRCDIR)) + +!exists($$GOOGLETEST_DIR):message("No googletest src dir found - set GOOGLETEST_DIR to enable.") + +DEFINES += \ + GTEST_LANG_CXX11 + +INCLUDEPATH *= \ + $$GTEST_SRCDIR \ + $$GTEST_SRCDIR/include \ + $$GMOCK_SRCDIR \ + $$GMOCK_SRCDIR/include + +SOURCES += \ + $$GTEST_SRCDIR/src/gtest-all.cc \ + $$GMOCK_SRCDIR/src/gmock-all.cc diff --git a/DRAMSys/unitTests/googletest b/DRAMSys/unitTests/googletest new file mode 160000 index 00000000..b77e5c76 --- /dev/null +++ b/DRAMSys/unitTests/googletest @@ -0,0 +1 @@ +Subproject commit b77e5c76252bac322bb82c5b444f050bd0d92451 diff --git a/DRAMSys/unitTests/main.cpp b/DRAMSys/unitTests/main.cpp new file mode 100644 index 00000000..e76b5f95 --- /dev/null +++ b/DRAMSys/unitTests/main.cpp @@ -0,0 +1,9 @@ +#include +#include +#include "Testfile.h" + +int sc_main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/DRAMSys/unitTests/unitTests.pro b/DRAMSys/unitTests/unitTests.pro new file mode 100644 index 00000000..375411e7 --- /dev/null +++ b/DRAMSys/unitTests/unitTests.pro @@ -0,0 +1,77 @@ +TARGET = unitTestsDRAMSys + +TEMPLATE = app +CONFIG += console +CONFIG -= app_bundle +CONFIG -= qt + +systemc_home = $$(SYSTEMC_HOME) +isEmpty(systemc_home) { + systemc_home = /opt/systemc +} +message(SystemC home is $${systemc_home}) + +systemc_target_arch = $$(SYSTEMC_TARGET_ARCH) +isEmpty(systemc_target_arch) { + systemc_target_arch = linux64 +} + +message(SystemC target architecture is $${systemc_target_arch}) + +dramsys_disable_coverage_check = $$(DRAMSYS_DISABLE_COVERAGE_CHECK) +isEmpty(dramsys_disable_coverage_check) { + coverage_check = true + message(Coverage check ENABLED) +} else { + coverage_check = false + message(Coverage check DISABLED) +} + +unix:!macx { + message(Building on a GNU/Linux) + QMAKE_RPATHDIR += $${systemc_home}/lib-$${systemc_target_arch} + message(Linker options QMAKE_RPATHDIR is $${QMAKE_RPATHDIR}) +} + +DEFINES += TIXML_USE_STL +DEFINES += SC_INCLUDE_DYNAMIC_PROCESSES + +unix:!macx { + QMAKE_CXXFLAGS += -std=c++11 -O0 -g + $$eval(coverage_check) { + QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage -fPIC -O0 + QMAKE_LFLAGS += -lgcov --coverage + } +} + +macx: { + CONFIG += c++11 + QMAKE_CXXFLAGS += -std=c++0x -stdlib=libc++ -O0 -g + $$eval(coverage_check) { + QMAKE_CXXFLAGS += --coverage + QMAKE_LFLAGS += --coverage + } +} + +QMAKE_CXXFLAGS += -pthread + +INCLUDEPATH += ../library/src/simulation/ +INCLUDEPATH += $${systemc_home}/include + +LIBS += -L$${systemc_home}/lib-$${systemc_target_arch} -lsystemc -lpthread + +SOURCEHOME = ../library/src/ + +SOURCES += \ + main.cpp \ + $${SOURCEHOME}/controller/Command.cpp + + +HEADERS += \ + Testfile.h \ + $${SOURCEHOME}/controller/Command.h + +DISTFILES += ../DRAMSys.astylerc + +include(googleTest.pri) +DISTFILES += googleTest.pri