diff --git a/dram/.cproject b/dram/.cproject index 49a1ca7b..79dda475 100644 --- a/dram/.cproject +++ b/dram/.cproject @@ -19,7 +19,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -91,6 +91,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dram/.settings/language.settings.xml b/dram/.settings/language.settings.xml index b20c7d94..26f9f756 100644 --- a/dram/.settings/language.settings.xml +++ b/dram/.settings/language.settings.xml @@ -10,4 +10,14 @@ + + + + + + + + + + diff --git a/dram/resources/configs/memconfigs/memconfig.xml b/dram/resources/configs/memconfigs/memconfig.xml index c1dc5677..e21c26b4 100644 --- a/dram/resources/configs/memconfigs/memconfig.xml +++ b/dram/resources/configs/memconfigs/memconfig.xml @@ -1,10 +1,10 @@ - + - + diff --git a/dram/src/common/DebugManager.cpp b/dram/src/common/DebugManager.cpp index 819c9195..f0f4b3b7 100644 --- a/dram/src/common/DebugManager.cpp +++ b/dram/src/common/DebugManager.cpp @@ -9,14 +9,9 @@ using namespace std; -DebugManager& DebugManager::getInstance() -{ - static DebugManager manager; - return manager; -} - void DebugManager::printDebugMessage(string sender, string message) { +#ifndef NDEBUG if (whiteList.count(sender)) { if (writeToConsole) @@ -25,6 +20,7 @@ void DebugManager::printDebugMessage(string sender, string message) if (writeToFile) debugFile << " at " << sc_time_stamp() << " in " << sender << "\t: " << message << "\n"; } +#endif } void DebugManager::addToWhiteList(string sender) diff --git a/dram/src/common/DebugManager.h b/dram/src/common/DebugManager.h index 0e82c1e8..e1d6f9cd 100644 --- a/dram/src/common/DebugManager.h +++ b/dram/src/common/DebugManager.h @@ -16,7 +16,11 @@ class DebugManager { public: ~DebugManager(); - static DebugManager& getInstance(); + static inline DebugManager& getInstance() + { + static DebugManager manager; + return manager; + } bool writeToConsole; bool writeToFile; diff --git a/dram/src/common/TlmRecorder.h b/dram/src/common/TlmRecorder.h index fba69078..81c9aeca 100755 --- a/dram/src/common/TlmRecorder.h +++ b/dram/src/common/TlmRecorder.h @@ -38,6 +38,7 @@ public: void recordMemconfig(string memconfig){this->memconfig = memconfig;} void recordMemspec(string memspec){this->memspec = memspec;} void recordTracenames(string traces){this->traces = traces;} + private: std::string memconfig,memspec,traces; TlmRecorder(); diff --git a/dram/src/common/Utils.cpp b/dram/src/common/Utils.cpp index c6e6a757..5c459204 100644 --- a/dram/src/common/Utils.cpp +++ b/dram/src/common/Utils.cpp @@ -29,9 +29,9 @@ unsigned int queryUIntParameter(XMLElement* node, string name) { if (element->Attribute("id") == name) { - assert(!strcmp(element->Attribute("type"), "uint")); + sc_assert(!strcmp(element->Attribute("type"), "uint")); XMLError error = element->QueryIntAttribute("value", &result); - assert(!error); + sc_assert(!error); return result; } } @@ -63,9 +63,9 @@ double queryDoubleParameter(XMLElement* node, string name) { if (element->Attribute("id") == name) { - assert(!strcmp(element->Attribute("type"), "double")); + sc_assert(!strcmp(element->Attribute("type"), "double")); XMLError error = element->QueryDoubleAttribute("value", &result); - assert(!error); + sc_assert(!error); return result; } } @@ -83,9 +83,9 @@ bool queryBoolParameter(XMLElement* node, string name) { if (element->Attribute("id") == name) { - assert(!strcmp(element->Attribute("type"), "bool")); + sc_assert(!strcmp(element->Attribute("type"), "bool")); XMLError error = element->QueryBoolAttribute("value", &result); - assert(!error); + sc_assert(!error); return result; } } diff --git a/dram/src/common/dramExtension.cpp b/dram/src/common/dramExtension.cpp index 46c59eee..0259c5ab 100644 --- a/dram/src/common/dramExtension.cpp +++ b/dram/src/common/dramExtension.cpp @@ -1,5 +1,4 @@ #include "dramExtension.h" -#include #include "../core/configuration/Configuration.h" #include "map" @@ -12,10 +11,8 @@ DramExtension& DramExtension::getExtension(const tlm_generic_payload *payload) { DramExtension *result = NULL; payload->get_extension(result); - if(result == NULL) - { - SC_REPORT_FATAL("DRAM Extension","Extension is null."); - } + sc_assert(result!=NULL); + return *result; } @@ -55,7 +52,7 @@ BankGroup Bank::getBankGroup() if (bankgroups.size() == 0) { core::Configuration& config = core::Configuration::getInstance(); - SC_ASSERT_(config.NumberOfBanks % config.NumberOfBankGroups == 0, "Number of banks must be a multiple of number of bankgroups"); + sc_assert(config.NumberOfBanks % config.NumberOfBankGroups == 0); for (unsigned int bank = 0; bank < config.NumberOfBanks; bank++) { diff --git a/dram/src/common/third_party/tinyxml2.h b/dram/src/common/third_party/tinyxml2.h index 0c764e9a..c8a69e47 100644 --- a/dram/src/common/third_party/tinyxml2.h +++ b/dram/src/common/third_party/tinyxml2.h @@ -81,7 +81,7 @@ distribution. # define TIXMLASSERT( x ) if ( !(x)) { __debugbreak(); } //if ( !(x)) WinDebugBreak() # elif defined (ANDROID_NDK) # include -# define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); } +# define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "assert in '%s' at %d.", __FILE__, __LINE__ ); } # else # include # define TIXMLASSERT assert diff --git a/dram/src/common/xmlAddressdecoder.cpp b/dram/src/common/xmlAddressdecoder.cpp index f81d5f47..84342e25 100644 --- a/dram/src/common/xmlAddressdecoder.cpp +++ b/dram/src/common/xmlAddressdecoder.cpp @@ -69,7 +69,7 @@ xmlAddressDecoder::xmlAddressDecoder(string addressConfigURI) } else { - SC_REPORT_ERROR("xmlAddressDecoder can not find ", addressConfigURI.c_str()); + SC_REPORT_FATAL("xmlAddressDecoder can not find ", addressConfigURI.c_str()); } } diff --git a/dram/src/core/ControllerCore.cpp b/dram/src/core/ControllerCore.cpp index 86abdbd9..0c3075c2 100644 --- a/dram/src/core/ControllerCore.cpp +++ b/dram/src/core/ControllerCore.cpp @@ -13,6 +13,7 @@ #include "scheduling/checker/ReadChecker.h" #include "scheduling/checker/WriteChecker.h" #include "scheduling/checker/RefreshChecker.h" +#include "scheduling/checker/PowerDownChecker.h" #include "refresh/RefreshManagerBankwise.h" #include "refresh/RefreshManager.h" #include "../common/dramExtension.h" @@ -39,6 +40,12 @@ ControllerCore::ControllerCore(IWrapperConnector& wrapperConnector, std::mapisInvalidated(payload, time) && !powerDownManager->isInSelfRefresh(bank)) { - printDebugMessage("Waking up bank " + to_string(bank.ID()) + " for refresh"); powerDownManager->wakeUpForRefresh(bank, time); //expects PDNA and PDNP to exit without delay refreshManager->scheduleRefresh(payload, time); } @@ -128,13 +135,14 @@ bool ControllerCore::isBusy(sc_time time, Bank bank) { return (time < lastScheduledCommand.getEnd()); } - else if (lastScheduledCommand.commandIsIn( { Command::SREFX, Command::PDNPX, Command::PDNAX })) + else if (lastScheduledCommand.commandIsIn( { Command::SREFX, Command::PDNPX, Command::PDNAX, Command::SREF, Command::PDNP, + Command::PDNA })) { return false; } else { - SC_ASSERT_(false, "last command in command sequence was activate or precharge"); + SC_REPORT_FATAL("Core", "Last command in command sequence was activate or precharge. This really doesn't make sense :D."); return false; } diff --git a/dram/src/core/configuration/MemSpecLoader.cpp b/dram/src/core/configuration/MemSpecLoader.cpp index 3f931833..7468aaf8 100644 --- a/dram/src/core/configuration/MemSpecLoader.cpp +++ b/dram/src/core/configuration/MemSpecLoader.cpp @@ -91,7 +91,9 @@ void MemSpecLoader::loadDDR4(Configuration& config, XMLElement* memspec) config.Timings.tCKESR = clk * queryUIntParameter(timings, "CKESR"); config.Timings.tCKE = clk * queryUIntParameter(timings, "CKE"); config.Timings.tXP = clk * queryUIntParameter(timings, "XP"); + config.Timings.tXPDLL = clk * queryUIntParameter(timings, "XPDLL"); config.Timings.tXSR = clk * queryUIntParameter(timings, "XS"); + config.Timings.tXSRDLL = clk * queryUIntParameter(timings, "XSDLL"); config.Timings.tAL = clk * queryUIntParameter(timings, "AL"); config.Timings.tRFC = clk * queryUIntParameter(timings, "RFC"); config.Timings.tREFI = clk * queryUIntParameter(timings, "REFI"); @@ -140,7 +142,9 @@ void MemSpecLoader::loadWideIO(Configuration& config, XMLElement* memspec) config.Timings.tCKESR = clk * queryUIntParameter(timings, "CKESR"); config.Timings.tCKE = clk * queryUIntParameter(timings, "CKE"); config.Timings.tXP = clk * queryUIntParameter(timings, "XP"); + config.Timings.tXPDLL = config.Timings.tXP; config.Timings.tXSR = clk * queryUIntParameter(timings, "XS"); + config.Timings.tXSRDLL = config.Timings.tXSR; config.Timings.tAL = clk * queryUIntParameter(timings, "AL"); config.Timings.tRFC = clk * queryUIntParameter(timings, "RFC"); config.Timings.tREFI = clk * queryUIntParameter(timings, "REFI"); diff --git a/dram/src/core/configuration/TimingConfiguration.h b/dram/src/core/configuration/TimingConfiguration.h index 64c336ed..7bac0d9a 100644 --- a/dram/src/core/configuration/TimingConfiguration.h +++ b/dram/src/core/configuration/TimingConfiguration.h @@ -46,7 +46,9 @@ struct TimingConfiguration 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 + sc_time tXSRDLL; //min delay to row access command after srefx for dll commands sc_time tAL; //additive delay (delayed execution in dram) sc_time tRFC; //min ref->act delay diff --git a/dram/src/core/powerdown/PowerDownManager.cpp b/dram/src/core/powerdown/PowerDownManager.cpp index 660c78df..2fe05836 100644 --- a/dram/src/core/powerdown/PowerDownManager.cpp +++ b/dram/src/core/powerdown/PowerDownManager.cpp @@ -59,11 +59,11 @@ void PowerDownManager::sleep(Bank bank, sc_time time) } } - ScheduledCommand pdn(IPowerDownManager::getSleepCommand(state), time, - getMinimalExecutionTime(IPowerDownManager::getSleepCommand(state), powerDownPayloads[bank]), + Command cmd = IPowerDownManager::getSleepCommand(state); + ScheduledCommand pdn(cmd, time, getMinimalExecutionTime(cmd, powerDownPayloads[bank]), DramExtension::getExtension(powerDownPayloads[bank])); - controller.state.bus.moveCommandToNextFreeSlot(pdn); + controller.getCommandChecker(cmd).delayToSatisfyConstraints(pdn); if (state != PowerDownState::PDNSelfRefresh && controller.refreshManager->hasCollision(pdn)) { @@ -71,7 +71,7 @@ void PowerDownManager::sleep(Bank bank, sc_time time) } else { - setState(state); + setPowerDownState(state); sendPowerDownPayloads(pdn); } } @@ -80,33 +80,19 @@ void PowerDownManager::wakeUp(Bank bank, sc_time time) { if (isAwakeForRefresh()) //Request enters system during Refresh { - setState(PowerDownState::Awake); + setPowerDownState(PowerDownState::Awake); } else if (isInPowerDown()) //Request wakes up power down { - sc_time startOfExitCommand(SC_ZERO_TIME); - switch (powerDownState) - { - case PowerDownState::PDNActive: - startOfExitCommand = max(time, controller.state.getLastCommand(Command::PDNA).getEnd()); - break; - case PowerDownState::PDNPrecharge: - startOfExitCommand = max(time, controller.state.getLastCommand(Command::PDNP).getEnd()); - break; - case PowerDownState::PDNSelfRefresh: - startOfExitCommand = max(time, controller.state.getLastCommand(Command::SREF).getEnd()); - controller.refreshManager->reInitialize(bank, - startOfExitCommand + getMinimalExecutionTime(Command::SREFX, powerDownPayloads[bank])); - break; - default: - break; - } - Command cmd = IPowerDownManager::getWakeUpCommand(powerDownState); - ScheduledCommand pdn(cmd, startOfExitCommand, getMinimalExecutionTime(cmd, powerDownPayloads[bank]), + ScheduledCommand pdn(cmd, time, getExecutionTime(cmd, powerDownPayloads[bank]), DramExtension::getExtension(powerDownPayloads[bank])); + controller.getCommandChecker(cmd).delayToSatisfyConstraints(pdn); - setState(PowerDownState::Awake); + if (cmd == Command::SREFX) + controller.refreshManager->reInitialize(bank, pdn.getEnd()); + + setPowerDownState(PowerDownState::Awake); sendPowerDownPayloads(pdn); } } @@ -116,10 +102,10 @@ void PowerDownManager::wakeUpForRefresh(Bank bank, sc_time time) if (isInPowerDown()) { Command cmd = IPowerDownManager::getWakeUpCommand(powerDownState); - ScheduledCommand pdn(cmd, time, getMinimalExecutionTime(cmd, powerDownPayloads[bank]), + ScheduledCommand pdn(cmd, time, getExecutionTime(cmd, powerDownPayloads[bank]), DramExtension::getExtension(powerDownPayloads[bank])); - setState(PowerDownState::AwakeForRefresh); + setPowerDownState(PowerDownState::AwakeForRefresh); sendPowerDownPayloads(pdn); } } @@ -137,7 +123,7 @@ void PowerDownManager::sendPowerDownPayloads(ScheduledCommand& cmd) } } -void PowerDownManager::setState(PowerDownState state) +void PowerDownManager::setPowerDownState(PowerDownState state) { powerDownState = state; DebugManager::getInstance().printDebugMessage(PowerDownManagerBankwise::senderName, diff --git a/dram/src/core/powerdown/PowerDownManager.h b/dram/src/core/powerdown/PowerDownManager.h index d7a25b5f..82a969c6 100644 --- a/dram/src/core/powerdown/PowerDownManager.h +++ b/dram/src/core/powerdown/PowerDownManager.h @@ -31,7 +31,7 @@ private: bool isInPowerDown(); - void setState(PowerDownState state); + void setPowerDownState(PowerDownState state); bool canSleep(); bool isAwakeForRefresh(); std::map powerDownPayloads; diff --git a/dram/src/core/powerdown/PowerDownManagerBankwise.cpp b/dram/src/core/powerdown/PowerDownManagerBankwise.cpp index 1a41a685..989bd4c3 100644 --- a/dram/src/core/powerdown/PowerDownManagerBankwise.cpp +++ b/dram/src/core/powerdown/PowerDownManagerBankwise.cpp @@ -32,7 +32,6 @@ void PowerDownManagerBankwise::sleep(Bank bank, sc_time time) return; tlm_generic_payload& payload = powerDownPayloads[bank]; - sc_time minTime = getMinimalExecutionTime(Command::PDNA, payload); PowerDownState state = powerDownStates[bank]; if (state == PowerDownState::Awake) //coming from active @@ -49,12 +48,12 @@ void PowerDownManagerBankwise::sleep(Bank bank, sc_time time) else { state = PowerDownState::PDNSelfRefresh; - minTime = getMinimalExecutionTime(Command::SREF, payload); } } - ScheduledCommand pdn(IPowerDownManager::getSleepCommand(state), time, minTime, DramExtension::getExtension(payload)); - controller.state.bus.moveCommandToNextFreeSlot(pdn); + Command cmd = IPowerDownManager::getSleepCommand(state); + ScheduledCommand pdn(cmd, time, getMinimalExecutionTime(cmd, payload), DramExtension::getExtension(payload)); + controller.getCommandChecker(cmd).delayToSatisfyConstraints(pdn); if (state != PowerDownState::PDNSelfRefresh && controller.refreshManager->hasCollision(pdn)) { @@ -76,27 +75,13 @@ void PowerDownManagerBankwise::wakeUp(Bank bank, sc_time time) else if (isInPowerDown(bank)) { //Request wakes up power down - sc_time startOfExitCommand(SC_ZERO_TIME); - switch (powerDownStates[bank]) - { - case PowerDownState::PDNActive: - startOfExitCommand = max(time, controller.state.getLastCommand(Command::PDNA).getEnd()); - break; - case PowerDownState::PDNPrecharge: - startOfExitCommand = max(time, controller.state.getLastCommand(Command::PDNP).getEnd()); - break; - case PowerDownState::PDNSelfRefresh: - startOfExitCommand = max(time, controller.state.getLastCommand(Command::SREF).getEnd()); - controller.refreshManager->reInitialize(bank, - startOfExitCommand + getExecutionTime(Command::SREFX, powerDownPayloads[bank])); - break; - default: - break; - } - Command cmd = IPowerDownManager::getWakeUpCommand(powerDownStates[bank]); - ScheduledCommand pdn(cmd, startOfExitCommand, getExecutionTime(cmd, powerDownPayloads[bank]), + ScheduledCommand pdn(cmd, time, getExecutionTime(cmd, powerDownPayloads[bank]), DramExtension::getExtension(powerDownPayloads[bank])); + controller.getCommandChecker(cmd).delayToSatisfyConstraints(pdn); + + if (cmd == Command::SREFX) + controller.refreshManager->reInitialize(bank, pdn.getEnd()); setState(PowerDownState::Awake, bank); sendPowerDownPayload(pdn); @@ -108,7 +93,8 @@ void PowerDownManagerBankwise::wakeUpForRefresh(Bank bank, sc_time time) if (isInPowerDown(bank)) { Command cmd = IPowerDownManager::getWakeUpCommand(powerDownStates[bank]); - ScheduledCommand pdn(cmd, time, getExecutionTime(cmd, powerDownPayloads[bank]), DramExtension::getExtension(powerDownPayloads[bank])); + ScheduledCommand pdn(cmd, time, getExecutionTime(cmd, powerDownPayloads[bank]), + DramExtension::getExtension(powerDownPayloads[bank])); setState(PowerDownState::AwakeForRefresh, bank); sendPowerDownPayload(pdn); diff --git a/dram/src/core/scheduling/checker/ActivateChecker.cpp b/dram/src/core/scheduling/checker/ActivateChecker.cpp index 3ad821df..f949bf2e 100644 --- a/dram/src/core/scheduling/checker/ActivateChecker.cpp +++ b/dram/src/core/scheduling/checker/ActivateChecker.cpp @@ -19,8 +19,8 @@ namespace core { void ActivateChecker::delayToSatisfyConstraints(ScheduledCommand& command) const { sc_assert(command.getCommand() == Command::Activate); - ScheduledCommand lastCommandOnBank = state.getLastScheduledCommand(command.getBank()); + ScheduledCommand lastCommandOnBank = state.getLastScheduledCommand(command.getBank()); if (lastCommandOnBank.isValidCommand()) { if (isIn(lastCommandOnBank.getCommand(), { Command::Precharge, Command::AutoRefresh, diff --git a/dram/src/core/scheduling/checker/PowerDownChecker.cpp b/dram/src/core/scheduling/checker/PowerDownChecker.cpp new file mode 100644 index 00000000..0acec216 --- /dev/null +++ b/dram/src/core/scheduling/checker/PowerDownChecker.cpp @@ -0,0 +1,44 @@ +/* + * PowerDownChecker.cpp + * + * Created on: Apr 11, 2014 + * Author: jonny + */ + +#include "PowerDownChecker.h" + +namespace core { +void PowerDownChecker::delayToSatisfyConstraints(ScheduledCommand& command) const +{ + sc_assert( + command.commandIsIn( + { Command::SREF, Command::PDNA, Command::PDNP, Command::PDNAX, Command::PDNPX, Command::SREFX })); + + if (command.commandIsIn( { Command::SREF, Command::PDNA, Command::PDNP })) + { + ScheduledCommand lastCommandOnBank = state.getLastScheduledCommand(command.getBank()); + + if (lastCommandOnBank.isValidCommand() + && lastCommandOnBank.commandIsIn( { Command::Read, Command::ReadA, Command::WriteA })) + { + command.delayToMeetConstraint(lastCommandOnBank.getEnd(), config.Timings.clk); + } + } + else if (command.getCommand() == Command::PDNAX) + { + command.delayToMeetConstraint(state.getLastCommand(Command::PDNA).getStart(), config.Timings.tCKE); + } + else if (command.getCommand() == Command::PDNPX) + { + command.delayToMeetConstraint(state.getLastCommand(Command::PDNP).getStart(), config.Timings.tCKE); + } + else if (command.getCommand() == Command::SREFX) + { + command.delayToMeetConstraint(state.getLastCommand(Command::SREF).getStart(), config.Timings.tCKESR); + } + + state.bus.moveCommandToNextFreeSlot(command); +} + +} /* namespace core */ + diff --git a/dram/src/core/scheduling/checker/PowerDownChecker.h b/dram/src/core/scheduling/checker/PowerDownChecker.h new file mode 100644 index 00000000..24784d13 --- /dev/null +++ b/dram/src/core/scheduling/checker/PowerDownChecker.h @@ -0,0 +1,38 @@ +/* + * PowerDownChecker.h + * + * Created on: Apr 11, 2014 + * Author: jonny + */ + +#ifndef POWERDOWNCHECKER_H_ +#define POWERDOWNCHECKER_H_ + +#include "../../ControllerState.h" +#include "../../configuration/Configuration.h" +#include "ICommandChecker.h" +#include + +namespace core { + +class PowerDownChecker : public ICommandChecker +{ +public: + PowerDownChecker(const Configuration& config, ControllerState& state) : + config(config), state(state) + { + } + virtual ~PowerDownChecker() + { + } + + virtual void delayToSatisfyConstraints(ScheduledCommand& command) const override; + +private: + const Configuration& config; + ControllerState& state; +}; + +} /* namespace core */ + +#endif /* POWERDOWNCHECKER_H_ */ diff --git a/dram/src/core/scheduling/checker/PrechargeAllChecker.cpp b/dram/src/core/scheduling/checker/PrechargeAllChecker.cpp index 780462a6..2a0d93d4 100644 --- a/dram/src/core/scheduling/checker/PrechargeAllChecker.cpp +++ b/dram/src/core/scheduling/checker/PrechargeAllChecker.cpp @@ -43,7 +43,6 @@ void PrechargeAllChecker::delayToSatisfyConstraints(ScheduledCommand& command) c } else if (lastCommand.commandIsIn( { Command::ReadA, Command::AutoRefresh })) { - command.delayToMeetConstraint(lastCommand.getEnd(), SC_ZERO_TIME); } else diff --git a/dram/src/core/scheduling/checker/PrechargeChecker.cpp b/dram/src/core/scheduling/checker/PrechargeChecker.cpp index a365f7d0..b3bff928 100644 --- a/dram/src/core/scheduling/checker/PrechargeChecker.cpp +++ b/dram/src/core/scheduling/checker/PrechargeChecker.cpp @@ -12,9 +12,7 @@ namespace core { void PrechargeChecker::delayToSatisfyConstraints(ScheduledCommand& command) const { - sc_assert( - command.getCommand() == Command::Precharge - || command.getCommand() == Command::PrechargeAll); + sc_assert(command.getCommand() == Command::Precharge); ScheduledCommand lastCommand = state.getLastScheduledCommand(command.getBank()); @@ -23,7 +21,7 @@ void PrechargeChecker::delayToSatisfyConstraints(ScheduledCommand& command) cons if (lastCommand.getCommand() == Command::Read) { command.delayToMeetConstraint(lastCommand.getStart(), - max(config.Timings.tRTP , lastCommand.getIntervalOnDataStrobe().getLength())); + max(config.Timings.tRTP, lastCommand.getIntervalOnDataStrobe().getLength())); } else if (lastCommand.getCommand() == Command::Write) { @@ -31,11 +29,10 @@ void PrechargeChecker::delayToSatisfyConstraints(ScheduledCommand& command) cons } else if (lastCommand.getCommand() == Command::PDNAX) { - command.delayToMeetConstraint(lastCommand.getEnd(), config.Timings.tXP);//TODO right? + command.delayToMeetConstraint(lastCommand.getEnd(), config.Timings.tXP); } else - reportFatal("Precharge Checker", - "Precharge can not follow " + commandToString(lastCommand.getCommand())); + reportFatal("Precharge Checker", "Precharge can not follow " + commandToString(lastCommand.getCommand())); } state.bus.moveCommandToNextFreeSlot(command); diff --git a/dram/src/core/scheduling/checker/ReadChecker.cpp b/dram/src/core/scheduling/checker/ReadChecker.cpp index 6536904a..52d5879b 100644 --- a/dram/src/core/scheduling/checker/ReadChecker.cpp +++ b/dram/src/core/scheduling/checker/ReadChecker.cpp @@ -13,7 +13,9 @@ namespace core { void ReadChecker::delayToSatisfyConstraints(ScheduledCommand& command) const { - assert(command.getCommand() == Command::Read || command.getCommand() == Command::ReadA); + sc_assert(command.getCommand() == Command::Read || command.getCommand() == Command::ReadA); + + delayToSatisfyDLL(command); ScheduledCommand lastCommand = state.getLastScheduledCommand(command.getBank()); @@ -27,9 +29,9 @@ void ReadChecker::delayToSatisfyConstraints(ScheduledCommand& command) const || lastCommand.getCommand() == Command::Write) { } - else if (lastCommand.getCommand() == Command::PDNAX) + else if (lastCommand.getCommand() == Command::PDNAX || lastCommand.getCommand() == Command::PDNPX) { - command.delayToMeetConstraint(lastCommand.getStart(), config.Timings.tXP);//TODO DLL also for PDNP and SREF .. not onyl last command + command.delayToMeetConstraint(lastCommand.getStart(), config.Timings.tXP);//TODO DLL ?? } else reportFatal("Read Checker", @@ -42,6 +44,7 @@ void ReadChecker::delayToSatisfyConstraints(ScheduledCommand& command) const } } + bool ReadChecker::collidesOnDataStrobe(ScheduledCommand& read) const { for (ScheduledCommand& strobeCommand : state.lastDataStrobeCommands) @@ -97,4 +100,12 @@ bool ReadChecker::collidesWithStrobeCommand(ScheduledCommand& read, } } +void ReadChecker::delayToSatisfyDLL(ScheduledCommand& read) const +{ + ScheduledCommand lastSREFX = state.getLastCommand(Command::SREFX, read.getBank()); + if(lastSREFX.isValidCommand()) + read.delayToMeetConstraint(lastSREFX.getStart(), config.Timings.tXSRDLL); +} + } /* namespace controller */ + diff --git a/dram/src/core/scheduling/checker/ReadChecker.h b/dram/src/core/scheduling/checker/ReadChecker.h index 58af651e..78508a79 100644 --- a/dram/src/core/scheduling/checker/ReadChecker.h +++ b/dram/src/core/scheduling/checker/ReadChecker.h @@ -25,6 +25,8 @@ public: private: const Configuration& config; ControllerState& state; + + void delayToSatisfyDLL(ScheduledCommand& read) const; bool collidesOnDataStrobe(ScheduledCommand& read) const; bool collidesWithStrobeCommand(ScheduledCommand& read, ScheduledCommand& strobeCommand) const; }; diff --git a/dram/src/core/scheduling/checker/WriteChecker.cpp b/dram/src/core/scheduling/checker/WriteChecker.cpp index ad8f86ac..36b946c1 100644 --- a/dram/src/core/scheduling/checker/WriteChecker.cpp +++ b/dram/src/core/scheduling/checker/WriteChecker.cpp @@ -13,7 +13,7 @@ namespace core { void WriteChecker::delayToSatisfyConstraints(ScheduledCommand& command) const { - assert(command.getCommand() == Command::Write || command.getCommand() == Command::WriteA); + sc_assert(command.getCommand() == Command::Write || command.getCommand() == Command::WriteA); ScheduledCommand lastCommand = state.getLastScheduledCommand(command.getBank()); @@ -23,8 +23,7 @@ void WriteChecker::delayToSatisfyConstraints(ScheduledCommand& command) const { command.delayToMeetConstraint(lastCommand.getEnd(), SC_ZERO_TIME); } - else if (lastCommand.getCommand() == Command::Read - || lastCommand.getCommand() == Command::Write) + else if (lastCommand.getCommand() == Command::Read || lastCommand.getCommand() == Command::Write) { } @@ -33,8 +32,7 @@ void WriteChecker::delayToSatisfyConstraints(ScheduledCommand& command) const command.delayToMeetConstraint(lastCommand.getStart(), config.Timings.tXP); } else - reportFatal("Write Checker", - "Write can not follow " + commandToString(lastCommand.getCommand())); + reportFatal("Write Checker", "Write can not follow " + commandToString(lastCommand.getCommand())); } while (!state.bus.isFree(command.getStart()) || collidesOnDataStrobe(command)) @@ -54,12 +52,10 @@ bool WriteChecker::collidesOnDataStrobe(ScheduledCommand& write) const return false; } -bool WriteChecker::collidesWithStrobeCommand(ScheduledCommand& write, - ScheduledCommand& strobeCommand) const +bool WriteChecker::collidesWithStrobeCommand(ScheduledCommand& write, ScheduledCommand& strobeCommand) const { //write to write - if (strobeCommand.getCommand() == Command::Write - || strobeCommand.getCommand() == Command::WriteA) + if (strobeCommand.getCommand() == Command::Write || strobeCommand.getCommand() == Command::WriteA) { bool collision = write.collidesOnDataStrobe(strobeCommand); @@ -70,8 +66,7 @@ bool WriteChecker::collidesWithStrobeCommand(ScheduledCommand& write, return collision || casToCas; } - else if (strobeCommand.getCommand() == Command::Read - || strobeCommand.getCommand() == Command::ReadA) + else if (strobeCommand.getCommand() == Command::Read || strobeCommand.getCommand() == Command::ReadA) { //write to read if (strobeCommand.getStart() >= write.getStart()) @@ -80,8 +75,7 @@ bool WriteChecker::collidesWithStrobeCommand(ScheduledCommand& write, (write.getBank().getBankGroup() == strobeCommand.getBank().getBankGroup()) ? config.Timings.tWTR_L : config.Timings.tWTR_S; - return strobeCommand.getStart() - < clkAlign(write.getIntervalOnDataStrobe().end, Alignment::DOWN) + tWTR; + return strobeCommand.getStart() < clkAlign(write.getIntervalOnDataStrobe().end, Alignment::DOWN) + tWTR; } //read to write else @@ -92,8 +86,7 @@ bool WriteChecker::collidesWithStrobeCommand(ScheduledCommand& write, else { reportFatal("Write Checker", - "Invalid strobeCommand in data strobe commands " - + commandToString(strobeCommand.getCommand())); + "Invalid strobeCommand in data strobe commands " + commandToString(strobeCommand.getCommand())); return true; } } diff --git a/dram/src/scheduler/Fr_Fcfs.cpp b/dram/src/scheduler/Fr_Fcfs.cpp index e59bef5a..3ca88d90 100644 --- a/dram/src/scheduler/Fr_Fcfs.cpp +++ b/dram/src/scheduler/Fr_Fcfs.cpp @@ -85,7 +85,7 @@ gp* FR_FCFS::getTransactionForBank(Bank bank) gp* FR_FCFS::popOldest(Bank bank) { - assert(hasTransactionForBank(bank)); + sc_assert(hasTransactionForBank(bank)); gp* result = buffer[bank].front(); buffer[bank].pop_front(); diff --git a/dram/src/scheduler/PARBS.cpp b/dram/src/scheduler/PARBS.cpp index 7e357870..ba7c88cc 100644 --- a/dram/src/scheduler/PARBS.cpp +++ b/dram/src/scheduler/PARBS.cpp @@ -49,7 +49,7 @@ void PAR_BS::schedule(gp* payload) gp* PAR_BS::getTransactionForBank(Bank bank) { - assert(hasTransactionForBank(bank)); + sc_assert(hasTransactionForBank(bank)); if (batch->isEmpty()) { diff --git a/dram/src/simulation/Controller.h b/dram/src/simulation/Controller.h index f578db2e..df9c96b1 100644 --- a/dram/src/simulation/Controller.h +++ b/dram/src/simulation/Controller.h @@ -42,8 +42,8 @@ public: tlm_utils::simple_target_socket tSocket; Controller(sc_module_name name) : - frontendPEQ(this, &Controller::frontendPEQCallback), dramPEQ(this, &Controller::dramPEQCallback), controllerPEQ(this, - &Controller::controllerCorePEQCallback), debugManager(DebugManager::getInstance()) + frontendPEQ(this, &Controller::frontendPEQCallback), dramPEQ(this, &Controller::dramPEQCallback), controllerCorePEQ( + this, &Controller::controllerCorePEQCallback), debugManager(DebugManager::getInstance()) { controller = new ControllerCore(*this, numberOfPayloadsInSystem); buildScheduler(); @@ -89,62 +89,60 @@ public: // ------- Interaction with controller core --------- virtual void send(const ScheduledCommand& command, tlm_generic_payload& payload) override { - assert(command.getStart() >= sc_time_stamp()); - + sc_assert(command.getStart() >= sc_time_stamp()); TimeInterval dataStrobe; - TlmRecorder& rec = TlmRecorder::getInstance(); switch (command.getCommand()) { case Command::Read: dataStrobe = command.getIntervalOnDataStrobe(); - rec.updateDataStrobe(dataStrobe.start, dataStrobe.end, payload); - controllerPEQ.notify(payload, BEGIN_RD, command.getStart() - sc_time_stamp()); + TlmRecorder::getInstance().updateDataStrobe(dataStrobe.start, dataStrobe.end, payload); + controllerCorePEQ.notify(payload, BEGIN_RD, command.getStart() - sc_time_stamp()); break; case Command::ReadA: dataStrobe = command.getIntervalOnDataStrobe(); - rec.updateDataStrobe(dataStrobe.start, dataStrobe.end, payload); - controllerPEQ.notify(payload, BEGIN_RDA, command.getStart() - sc_time_stamp()); + TlmRecorder::getInstance().updateDataStrobe(dataStrobe.start, dataStrobe.end, payload); + controllerCorePEQ.notify(payload, BEGIN_RDA, command.getStart() - sc_time_stamp()); break; case Command::Write: dataStrobe = command.getIntervalOnDataStrobe(); - rec.updateDataStrobe(dataStrobe.start, dataStrobe.end, payload); - controllerPEQ.notify(payload, BEGIN_WR, command.getStart() - sc_time_stamp()); + TlmRecorder::getInstance().updateDataStrobe(dataStrobe.start, dataStrobe.end, payload); + controllerCorePEQ.notify(payload, BEGIN_WR, command.getStart() - sc_time_stamp()); break; case Command::WriteA: dataStrobe = command.getIntervalOnDataStrobe(); - rec.updateDataStrobe(dataStrobe.start, dataStrobe.end, payload); - controllerPEQ.notify(payload, BEGIN_WRA, command.getStart() - sc_time_stamp()); + TlmRecorder::getInstance().updateDataStrobe(dataStrobe.start, dataStrobe.end, payload); + controllerCorePEQ.notify(payload, BEGIN_WRA, command.getStart() - sc_time_stamp()); break; case Command::AutoRefresh: - controllerPEQ.notify(payload, BEGIN_AUTO_REFRESH, command.getStart() - sc_time_stamp()); + controllerCorePEQ.notify(payload, BEGIN_AUTO_REFRESH, command.getStart() - sc_time_stamp()); break; case Command::Activate: - controllerPEQ.notify(payload, BEGIN_ACT, command.getStart() - sc_time_stamp()); + controllerCorePEQ.notify(payload, BEGIN_ACT, command.getStart() - sc_time_stamp()); break; case Command::Precharge: - controllerPEQ.notify(payload, BEGIN_PRE, command.getStart() - sc_time_stamp()); + controllerCorePEQ.notify(payload, BEGIN_PRE, command.getStart() - sc_time_stamp()); break; case Command::PrechargeAll: - controllerPEQ.notify(payload, BEGIN_PRE_ALL, command.getStart() - sc_time_stamp()); + controllerCorePEQ.notify(payload, BEGIN_PRE_ALL, command.getStart() - sc_time_stamp()); break; case Command::PDNA: - controllerPEQ.notify(payload, BEGIN_PDNA, command.getStart() - sc_time_stamp()); + controllerCorePEQ.notify(payload, BEGIN_PDNA, command.getStart() - sc_time_stamp()); break; case Command::PDNP: - controllerPEQ.notify(payload, BEGIN_PDNP, command.getStart() - sc_time_stamp()); + controllerCorePEQ.notify(payload, BEGIN_PDNP, command.getStart() - sc_time_stamp()); break; case Command::SREF: - controllerPEQ.notify(payload, BEGIN_SREF, command.getStart() - sc_time_stamp()); + controllerCorePEQ.notify(payload, BEGIN_SREF, command.getStart() - sc_time_stamp()); break; case Command::PDNAX: - controllerPEQ.notify(payload, END_PDNA, command.getEnd() - sc_time_stamp()); + controllerCorePEQ.notify(payload, END_PDNA, command.getEnd() - sc_time_stamp()); break; case Command::PDNPX: - controllerPEQ.notify(payload, END_PDNP, command.getEnd() - sc_time_stamp()); + controllerCorePEQ.notify(payload, END_PDNP, command.getEnd() - sc_time_stamp()); break; case Command::SREFX: - dramPEQ.notify(payload, END_SREF, command.getEnd() - sc_time_stamp()); + controllerCorePEQ.notify(payload, END_SREF, command.getEnd() - sc_time_stamp()); break; default: @@ -155,12 +153,12 @@ public: virtual void send(Trigger trigger, sc_time time, tlm_generic_payload& payload) override { - assert(time >= sc_time_stamp()); + sc_assert(time >= sc_time_stamp()); sc_time delay = time - sc_time_stamp(); if (trigger == Trigger::RefreshTrigger) { - controllerPEQ.notify(payload, REFRESH_TRIGGER, delay); + controllerCorePEQ.notify(payload, REFRESH_TRIGGER, delay); } else { @@ -178,19 +176,19 @@ public: { Bank bank = DramExtension::getExtension(payload).getBank(); TlmRecorder::getInstance().recordPhase(payload, phase, sc_time_stamp()); - sendToDram(payload, phase, SC_ZERO_TIME); - if (phase == BEGIN_RD || phase == BEGIN_WR) - scheduleNextPayload(bank); - else if (isIn(phase, { BEGIN_ACT, BEGIN_PRE, BEGIN_PRE_ALL, BEGIN_RDA, BEGIN_WRA })) + if (isIn(phase, { BEGIN_RD, BEGIN_WR, BEGIN_ACT, BEGIN_PRE, BEGIN_PRE_ALL, BEGIN_RDA, BEGIN_WRA, BEGIN_AUTO_REFRESH })) { + sendToDram(payload, phase, SC_ZERO_TIME); + if (phase == BEGIN_RD || phase == BEGIN_WR) + scheduleNextPayload(bank); + else if (phase == BEGIN_AUTO_REFRESH) + printDebugMessage("Entering auto refresh on bank " + to_string(bank.ID())); } else if (isIn(phase, { BEGIN_PDNA, BEGIN_PDNP, BEGIN_SREF })) printDebugMessage("Entering PowerDown " + phaseNameToString(phase) + " on bank " + to_string(bank.ID())); else if (isIn(phase, { END_PDNA, END_PDNP, END_SREF })) printDebugMessage("Leaving PowerDown " + phaseNameToString(phase) + " on bank " + to_string(bank.ID())); - else if (phase == BEGIN_AUTO_REFRESH) - printDebugMessage("Entering auto refresh on bank " + to_string(bank.ID())); else SC_REPORT_FATAL(0, "refreshTriggerPEQCallback queue in controller wrapper was triggered with unsupported phase"); } @@ -205,7 +203,7 @@ private: tlm_utils::peq_with_cb_and_phase frontendPEQ; tlm_utils::peq_with_cb_and_phase dramPEQ; - tlm_utils::peq_with_cb_and_phase controllerPEQ; + tlm_utils::peq_with_cb_and_phase controllerCorePEQ; DebugManager& debugManager; @@ -213,7 +211,6 @@ private: tlm_sync_enum nb_transport_fw(tlm_generic_payload& payload, tlm_phase& phase, sc_time& fwDelay) { - DramExtension::getExtension(payload); TlmRecorder::getInstance().recordPhase(payload, phase, sc_time_stamp()); if (phase == BEGIN_REQ) @@ -221,7 +218,7 @@ private: payload.acquire(); payloadEntersSystem(payload); - if (getNumberOfPayloadsInSystem() > controller->config.MaxNrOfTransactions) + if (getTotalNumberOfPayloadsInSystem() > controller->config.MaxNrOfTransactions) { printDebugMessage("##Backpressure: Max number of transactions in system reached"); backpressure = &payload; @@ -267,7 +264,9 @@ private: void payloadEntersSystem(tlm_generic_payload& payload) { Bank bank = DramExtension::getExtension(payload).getBank(); - printDebugMessage("Transaction enters system on bank " + to_string(bank.ID())); + printDebugMessage( + "Payload enters system on bank " + to_string(bank.ID()) + ". Total number of payloads in Controller: " + + to_string(getTotalNumberOfPayloadsInSystem())); numberOfPayloadsInSystem[bank]++; } @@ -276,9 +275,13 @@ private: Bank bank = DramExtension::getExtension(payload).getBank(); numberOfPayloadsInSystem[bank]--; controller->powerDownManager->sleep(bank, sc_time_stamp()); + printDebugMessage( + "Payload left system on bank " + to_string(bank.ID()) + ". Total number of payloads in Controller: " + + to_string(getTotalNumberOfPayloadsInSystem())); + } - unsigned int getNumberOfPayloadsInSystem() + unsigned int getTotalNumberOfPayloadsInSystem() { unsigned int sum = 0; for (Bank bank : controller->getBanks()) @@ -293,6 +296,7 @@ private: printDebugMessage("Triggering schedule next payload on bank " + to_string(bank.ID())); if (scheduler->hasTransactionForBank(bank)) { + controller->powerDownManager->wakeUp(bank, sc_time_stamp()); if (controller->isBusy(sc_time_stamp(), bank)) { @@ -300,8 +304,6 @@ private: return; } - controller->powerDownManager->wakeUp(bank, sc_time_stamp()); - tlm_generic_payload* nextTransaction = scheduler->getTransactionForBank(bank); if (controller->scheduleRequest(sc_time_stamp(), *nextTransaction)) { @@ -339,6 +341,7 @@ private: { TlmRecorder::getInstance().recordPhase(payload, phase, sc_time_stamp()); Bank bank = DramExtension::getExtension(payload).getBank(); + printDebugMessage("Received " + phaseNameToString(phase) + " from DRAM"); if (phase == END_RD || phase == END_WR || phase == END_RDA || phase == END_WRA) { diff --git a/dram/src/simulation/Dram.h b/dram/src/simulation/Dram.h index bd84ef3b..2473133a 100644 --- a/dram/src/simulation/Dram.h +++ b/dram/src/simulation/Dram.h @@ -13,8 +13,10 @@ #include #include #include +#include "../common/DebugManager.h" #include "../core/TimingCalculation.h" #include "../common/protocol.h" +#include "../common/Utils.h" using namespace std; using namespace tlm; @@ -24,12 +26,11 @@ template tSocket; - sc_event target_done_event; - tlm_utils::peq_with_cb_and_phase m_peq; + tlm_utils::peq_with_cb_and_phase controllePEQ; - SC_CTOR(Dram) : tSocket("socket") ,m_peq(this, &Dram::peq_cb) + SC_CTOR(Dram) : tSocket("socket") ,controllePEQ(this, &Dram::controllerPEQCallback) { - tSocket.register_nb_transport_fw(this, &Dram::nb_transport_fw); + tSocket.register_nb_transport_fw(this, &Dram::nb_transport_fw); } ~Dram() @@ -39,43 +40,43 @@ struct Dram: sc_module virtual tlm::tlm_sync_enum nb_transport_fw( tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_time& delay ) { - m_peq.notify( trans, phase, delay); + controllePEQ.notify(trans, phase, delay); return tlm::TLM_ACCEPTED; } - void peq_cb(tlm::tlm_generic_payload& payload, const tlm::tlm_phase& phase) + void controllerPEQCallback(tlm::tlm_generic_payload& payload, const tlm::tlm_phase& phase) { if(phase == BEGIN_PRE) { - sendToController(payload,phase, getExecutionTime(Command::Precharge, payload)); + sendToController(payload, END_PRE, getExecutionTime(Command::Precharge, payload)); } else if (phase == BEGIN_PRE_ALL) { - sendToController(payload,phase, getExecutionTime(Command::PrechargeAll, payload)); + sendToController(payload, END_PRE_ALL, getExecutionTime(Command::PrechargeAll, payload)); } else if(phase == BEGIN_ACT) { - sendToController(payload,phase, getExecutionTime(Command::Activate, payload)); + sendToController(payload, END_ACT, getExecutionTime(Command::Activate, payload)); } else if(phase == BEGIN_WR) { - sendToController(payload,phase, getExecutionTime(Command::Write, payload)); + sendToController(payload, END_WR, getExecutionTime(Command::Write, payload)); } else if(phase == BEGIN_RD) { - sendToController(payload,phase, getExecutionTime(Command::Read, payload)); + sendToController(payload, END_RD, getExecutionTime(Command::Read, payload)); } else if(phase == BEGIN_WRA) { - sendToController(payload,phase, getExecutionTime(Command::WriteA, payload)); + sendToController(payload, END_WRA, getExecutionTime(Command::WriteA, payload)); } else if(phase == BEGIN_RDA) { - sendToController(payload,phase, getExecutionTime(Command::ReadA, payload)); + sendToController(payload, END_RDA, getExecutionTime(Command::ReadA, payload)); } else if(phase == BEGIN_AUTO_REFRESH) { - sendToController(payload,phase, getExecutionTime(Command::AutoRefresh, payload)); + sendToController(payload, END_AUTO_REFRESH, getExecutionTime(Command::AutoRefresh, payload)); } //Powerdown phases have to be started and ended by the controller, because they do not have a fixed length @@ -112,11 +113,16 @@ struct Dram: sc_module void sendToController(tlm_generic_payload& payload, const tlm_phase& phase, const sc_time& delay) { - DramExtension::getExtension(payload); tlm_phase TPhase = phase; sc_time TDelay = delay; tSocket->nb_transport_bw(payload, TPhase, TDelay); } + + void printDebugMessage(string message) + { + DebugManager::getInstance().printDebugMessage(name(), message); + } + }; diff --git a/dram/src/simulation/SimulationManager.cpp b/dram/src/simulation/SimulationManager.cpp index 4099e197..58b103a1 100644 --- a/dram/src/simulation/SimulationManager.cpp +++ b/dram/src/simulation/SimulationManager.cpp @@ -56,6 +56,7 @@ Simulation::Simulation(sc_module_name name, string pathToResources, string trace if (!silent) { whiteList.push_back(controller->name()); + whiteList.push_back(dram->name()); whiteList.push_back(player2->name()); whiteList.push_back(player1->name()); whiteList.push_back(this->name()); diff --git a/dram/src/simulation/main.cpp b/dram/src/simulation/main.cpp index b48cc665..4b77a52c 100644 --- a/dram/src/simulation/main.cpp +++ b/dram/src/simulation/main.cpp @@ -82,7 +82,6 @@ int sc_main(int argc, char **argv) DramSetup setup; setup.memconfig = "memconfig.xml"; setup.memspec = "MatzesWideIO.xml"; - //setup.memspec = "MICRON_4Gb_DDR4-1866_8bit_A.xml"; DramSetup setup2; setup2.memconfig = "memconfig.xml"; @@ -95,11 +94,10 @@ int sc_main(int argc, char **argv) //batchTraces(setup, tracePairs); //batchSetups(tracePairs[0], {setup}); - string traceName("tpr.tdb"); + string traceName("tpr5.tdb"); string trace2 = "empty.stl"; string trace1 = "mediabench-g721encode_32.stl"; - //trace1 = "trace.stl"; if (runSimulation(resources, traceName, setup, { Device(trace1), Device(trace2) }))