diff --git a/dram/resources/simulations/sim-batch.xml b/dram/resources/simulations/sim-batch.xml index 43e20eed..0362bd10 100644 --- a/dram/resources/simulations/sim-batch.xml +++ b/dram/resources/simulations/sim-batch.xml @@ -3,6 +3,8 @@ + + @@ -11,12 +13,12 @@ - + - chstone-adpcm_32.stl + voco2.stl diff --git a/dram/src/controller/core/configuration/Configuration.cpp b/dram/src/controller/core/configuration/Configuration.cpp index 8b1d926f..aa321acd 100644 --- a/dram/src/controller/core/configuration/Configuration.cpp +++ b/dram/src/controller/core/configuration/Configuration.cpp @@ -32,6 +32,7 @@ * Authors: * Janik Schlemminger * Matthias Jung + * Eder F. Zulian */ #include "Configuration.h" @@ -123,6 +124,10 @@ void Configuration::setParameter(std::string name, std::string value) ErrorCSVFile = value; else if(name == "ErrorStoreMode") ErrorStoreMode = StringToEnum(value); + else if (name == "NumberOfTracePlayers") + NumberOfTracePlayers = string2int(value); + else if (name == "NumberOfMemChannels") + NumberOfMemChannels = string2int(value); else { SC_REPORT_FATAL("Configuration", ("Parameter " + name + " not defined in Configuration").c_str()); diff --git a/dram/src/controller/core/configuration/Configuration.h b/dram/src/controller/core/configuration/Configuration.h index 7cdab17c..37108792 100644 --- a/dram/src/controller/core/configuration/Configuration.h +++ b/dram/src/controller/core/configuration/Configuration.h @@ -32,6 +32,7 @@ * Authors: * Janik Schlemminger * Matthias Jung + * Eder F. Zulian */ #ifndef CONFIGURATION_H_ @@ -72,6 +73,8 @@ struct Configuration bool DatabaseRecording = true; bool PowerAnalysis = false; bool Debug = false; + unsigned int NumberOfTracePlayers = 4; + unsigned int NumberOfMemChannels = 1; //MemSpec(from DRAM-Power XML) MemSpec memSpec; diff --git a/dram/src/simulation/Arbiter.h b/dram/src/simulation/Arbiter.h index 69215235..2c8d096a 100644 --- a/dram/src/simulation/Arbiter.h +++ b/dram/src/simulation/Arbiter.h @@ -38,70 +38,81 @@ #ifndef ARBITER_H_ #define ARBITER_H_ -#include #include #include #include -#include -#include +#include +#include +#include +#include #include #include "../common/xmlAddressdecoder.h" #include "../common/dramExtension.h" #include "../controller/core/TimingCalculation.h" +#include "../controller/core/configuration/ConfigurationLoader.h" using namespace std; using namespace tlm; -template< - unsigned int NUMBER_OF_THREADS = 1, - unsigned int BUSWIDTH = 128, - unsigned int NUMBER_OF_CHANNELS = 1 -> +template struct Arbiter: public sc_module { public: - tlm_utils::simple_initiator_socket_tagged iSocket[NUMBER_OF_CHANNELS]; - tlm_utils::simple_target_socket_tagged tSockets[NUMBER_OF_THREADS]; + tlm_utils::multi_passthrough_initiator_socket iSocket; + tlm_utils::multi_passthrough_target_socket tSocket; SC_CTOR(Arbiter) : payloadEventQueue(this, &Arbiter::peqCallback) { - for (unsigned int i = 0; i < NUMBER_OF_CHANNELS; ++i) { - // The arbiter communicates with one or more memory controller through one or more sockets (one or more memory channels). - // Each of the arbiter's iniitator sockets is binded to a memory controller's target socket. - // In this case the arbiter is the initiator. - iSocket[i].register_nb_transport_bw(this, &Arbiter::nb_transport_bw, i); - channelIsFree[i] = true; + // 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()); } - for (unsigned int i = 0; i < NUMBER_OF_THREADS; ++i) { - // One or more devices can accesss the memory throught the arbiter. A device can be a processor's core, the execution of a previously recorded trace file, etc. - // As soon the arbiter receives a request in any of its target sockets it should treat and forward it to the proper memory channel. - // In this case the arbiter acts as a target. - tSockets[i].register_nb_transport_fw(this, &Arbiter::nb_transport_fw, i); + + // 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); + + for (size_t i = 0; i < Configuration::getInstance().NumberOfTracePlayers; ++i) { + receivedResponses.push_back(queue()); } } private: tlm_utils::peq_with_cb_and_phase payloadEventQueue; - bool channelIsFree[NUMBER_OF_CHANNELS]; + + vector channelIsFree; + //used to account for the request_accept_delay in the dram controllers - deque pendingRequests[NUMBER_OF_CHANNELS]; + // 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.) - deque receivedResponses[NUMBER_OF_THREADS]; + // This is a queue of responses comming from the memory side. The phase of these transactions is BEGIN_RESP. + vector> receivedResponses; // Initiated by dram side - tlm_sync_enum nb_transport_bw(__attribute__((unused)) int socketId, tlm_generic_payload& payload, tlm_phase& phase, sc_time& bwDelay) + // This function is called when an arbiter's initiator socket receives a transaction from a memory controller + tlm_sync_enum nb_transport_bw(__attribute__((unused)) int id, tlm_generic_payload& payload, tlm_phase& phase, sc_time& bwDelay) { TlmRecorder::getInstance().recordPhase(payload, phase, bwDelay + sc_time_stamp()); payloadEventQueue.notify(payload, phase, bwDelay); return TLM_ACCEPTED; } + // TODO: check this id. How the payload extension propagates and is used... + // TODO: check the index mechanism for initiator and target sockets. Assert the index to be valid. + // Initiated by initiator side - // Anytime the arbiter receives a message from a device this callback function is called - tlm_sync_enum nb_transport_fw(int socketId, tlm_generic_payload& payload, tlm_phase& phase, sc_time& fwDelay) + // 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) { if (phase == BEGIN_REQ) { // In the begin request phase the socket ID is appended to the payload. // It will extracted from the payload and used later. - appendDramExtension(socketId, payload); + appendDramExtension(id, payload); payload.acquire(); } else if (phase == END_RESP) { payload.release(); @@ -116,55 +127,54 @@ private: unsigned int initiatorSocket = DramExtension::getExtension(payload).getThread().ID()-1; unsigned int channelId = DramExtension::getExtension(payload).getChannel().ID(); + // TODO: here check if the channel and the initiatorSocket ID are valid. If not, the payload extension was corrupted. + // 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]) { - // If the channel is available forward the request to the memory controller + // This channel was available. Forward the new transaction to the memory controller. channelIsFree[channelId] = false; sendToChannel(channelId, payload, phase, SC_ZERO_TIME); } else { - // If the channel is not available put the request in a queue. - pendingRequests[channelId].push_back(&payload); + // 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_front(); + receivedResponses[initiatorSocket].pop(); - // Check if there are queued BEGIN_RESP messages from memory to this device + // 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(); + 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 controllers) + // 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 an END_REQ from memory controller and - // forward it to the requester device. + // 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 queued BEGIN_REQ, if any. Send it to the memory controller. + // 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_front(); - // Send ONE enqueued BEGIN_REQ to throgh this channel. + 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 BEGIN_RESP from memory controller and - // forwards it to the requester device + // 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 BEGIN_RESP. It will be dequeued later on when the - // initiator device sends an END_RESP - receivedResponses[initiatorSocket].push_back(&payload); + // Enqueue the transaction in BEGIN_RESP phase until the initiator device acknowledge it (phase changes to END_RESP). + receivedResponses[initiatorSocket].push(&payload); } else { SC_REPORT_FATAL(0, "Payload event queue in arbiter was triggered with unknown phase"); } @@ -181,11 +191,13 @@ private: { tlm_phase TPhase = phase; sc_time TDelay = delay; - tSockets[id]->nb_transport_bw(payload, TPhase, TDelay); + tSocket[id]->nb_transport_bw(payload, TPhase, TDelay); } void appendDramExtension(int socketId, tlm_generic_payload& payload) { + // TODO: check if channel valid before appending. + // TODO: check if all parts of the decodedAddress are inside the valid range (devices should not perform invalid requests to the arbiter, right?). unsigned int burstlength = payload.get_streaming_width(); DecodedAddress decodedAddress = xmlAddressDecoder::getInstance().decodeAddress(payload.get_address()); DramExtension* extension = new DramExtension(Thread(socketId+1), Channel(decodedAddress.channel), Bank(decodedAddress.bank), BankGroup(decodedAddress.bankgroup), Row(decodedAddress.row), Column(decodedAddress.column),burstlength); diff --git a/dram/src/simulation/Simulation.cpp b/dram/src/simulation/Simulation.cpp index 63123c04..98003184 100644 --- a/dram/src/simulation/Simulation.cpp +++ b/dram/src/simulation/Simulation.cpp @@ -90,7 +90,14 @@ void Simulation::setupTlmRecorder(const string &traceName, const string &pathToR TlmRecorder::sqlScriptURI = pathToResources + string("scripts/createTraceDB.sql"); TlmRecorder::getInstance().recordMemconfig(Configuration::getInstance().memconfigUri); TlmRecorder::getInstance().recordMemspec(Configuration::getInstance().memspecUri); - TlmRecorder::getInstance().recordTracenames(devices[0].trace + "," + devices[1].trace + "," + devices[2].trace + "," + devices[3].trace); + std::string traceNames; + for (size_t i = 0; i < devices.size(); i++) { + traceNames.append(devices[i].trace); + if (i == devices.size() - 1) + continue; + traceNames.append(","); + } + TlmRecorder::getInstance().recordTracenames(traceNames); } else { @@ -100,15 +107,15 @@ void Simulation::setupTlmRecorder(const string &traceName, const string &pathToR void Simulation::instantiateModules(const string &pathToResources, const std::vector& devices) { - for (size_t i = 0; i < NumberOfTracePlayers; i++) { + for (size_t i = 0; i < Configuration::getInstance().NumberOfTracePlayers; i++) { std::string playerStr = "player" + std::to_string(i); TracePlayer<> *player = new StlPlayer<>(playerStr.c_str(), pathToResources + string("traces/") + devices[i].trace, devices[i].clkMhz, this); players.push_back(player); } - arbiter = new Arbiter("arbiter"); + arbiter = new Arbiter<128>("arbiter"); - for (size_t i = 0; i < NumberOfMemChannels; i++) { + for (size_t i = 0; i < Configuration::getInstance().NumberOfMemChannels; i++) { std::string str = "controller" + std::to_string(i); Controller<> *controller = new Controller<>(str.c_str()); controllers.push_back(controller); @@ -123,11 +130,11 @@ void Simulation::bindSockets() { size_t i = 0; for (auto player : players) { - player->iSocket.bind(arbiter->tSockets[i++]); + player->iSocket.bind(arbiter->tSocket); } - for (i = 0; i < NumberOfMemChannels; i++) { - arbiter->iSocket[i].bind(controllers[i]->tSocket); + for (i = 0; i < Configuration::getInstance().NumberOfMemChannels; i++) { + arbiter->iSocket.bind(controllers[i]->tSocket); controllers[i]->iSocket.bind(drams[i]->tSocket); } } @@ -171,11 +178,10 @@ void inline Simulation::tracePlayerTerminates() static unsigned int finishedTracePlayers = 0; finishedTracePlayers++; - if (finishedTracePlayers == NumberOfTracePlayers) - { + if (finishedTracePlayers == Configuration::getInstance().NumberOfTracePlayers) terminateSimulation.notify(); - } } + void Simulation::stop() { wait(terminateSimulation); @@ -196,3 +202,4 @@ void Simulation::report(string message) DebugManager::getInstance().printDebugMessage(this->name(), message); cout << message << endl; } + diff --git a/dram/src/simulation/Simulation.h b/dram/src/simulation/Simulation.h index bcc276ed..09b14ad5 100644 --- a/dram/src/simulation/Simulation.h +++ b/dram/src/simulation/Simulation.h @@ -86,10 +86,6 @@ public: void stop(); virtual void tracePlayerTerminates() override; - // TODO: this information should be get from configuration - constexpr static unsigned int NumberOfTracePlayers = 4; - // TODO: this information should be get from configuration - constexpr static unsigned int NumberOfMemChannels = 1; private: std::string traceName; @@ -101,7 +97,7 @@ private: // and initiate transactions targeting the memory) std::vector*> players; // All transactions pass through the same arbiter - Arbiter *arbiter; + Arbiter<> *arbiter; // Each DRAM unit has a controller std::vector*> controllers; // TODO: Each DRAM has a reorder buffer (check this!) diff --git a/dram/src/simulation/SimulationManager.cpp b/dram/src/simulation/SimulationManager.cpp index 396619ad..94909b49 100644 --- a/dram/src/simulation/SimulationManager.cpp +++ b/dram/src/simulation/SimulationManager.cpp @@ -162,12 +162,10 @@ void SimulationManager::startTraceAnalyzer() void SimulationManager::addTraceSetup(SimulationBatch& batch, tinyxml2::XMLElement* element) { vector devices; - for (XMLElement* device = element->FirstChildElement("device"); device != NULL; device = device->NextSiblingElement("device")) - { + for (XMLElement* device = element->FirstChildElement("device"); device != NULL; device = device->NextSiblingElement("device")) { devices.push_back(Device(device->GetText(), device->IntAttribute("clkMhz"), device->IntAttribute("bl"))); } - while (devices.size() < Simulation::NumberOfTracePlayers) - { + while (devices.size() < Configuration::getInstance().NumberOfTracePlayers) { devices.push_back(Device()); }