Get number of trace players and number of channes from config.
- Using multi_passthrough_sockets in the arbiter. - Trace players, controllers and arbiter's queues are allocated dynamically.
This commit is contained in:
@@ -3,6 +3,8 @@
|
||||
<Debug value="1" />
|
||||
<DatabaseRecording value="1" />
|
||||
<PowerAnalysis value="1" />
|
||||
<NumberOfTracePlayers value="4"/>
|
||||
<NumberOfMemChannels value="1"/>
|
||||
</simconfig>
|
||||
<memspecs>
|
||||
<memspec src="../resources/configs/memspecs/WideIO.xml"></memspec>
|
||||
@@ -11,12 +13,12 @@
|
||||
<addressmapping src="../resources/configs/amconfigs/am_wideio.xml"></addressmapping>
|
||||
</addressmappings>
|
||||
<memconfigs>
|
||||
<memconfig src="../resources/configs/memconfigs/fr_fcfs.xml"/>
|
||||
<memconfig src="../resources/configs/memconfigs/fifo.xml"/>
|
||||
</memconfigs>
|
||||
|
||||
<tracesetups>
|
||||
<tracesetup id="fifo">
|
||||
<device clkMhz="200">chstone-adpcm_32.stl</device>
|
||||
<device clkMhz="200">voco2.stl</device>
|
||||
</tracesetup>
|
||||
</tracesetups>
|
||||
</simulation>
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -38,70 +38,81 @@
|
||||
#ifndef ARBITER_H_
|
||||
#define ARBITER_H_
|
||||
|
||||
#include <deque>
|
||||
#include <tlm.h>
|
||||
#include <systemc.h>
|
||||
#include <iostream>
|
||||
#include <tlm_utils/simple_target_socket.h>
|
||||
#include <tlm_utils/simple_initiator_socket.h>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <tlm_utils/multi_passthrough_target_socket.h>
|
||||
#include <tlm_utils/multi_passthrough_initiator_socket.h>
|
||||
#include <tlm_utils/peq_with_cb_and_phase.h>
|
||||
#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<unsigned int BUSWIDTH = 128>
|
||||
struct Arbiter: public sc_module {
|
||||
public:
|
||||
tlm_utils::simple_initiator_socket_tagged<Arbiter, BUSWIDTH, tlm::tlm_base_protocol_types> iSocket[NUMBER_OF_CHANNELS];
|
||||
tlm_utils::simple_target_socket_tagged<Arbiter, BUSWIDTH, tlm::tlm_base_protocol_types> tSockets[NUMBER_OF_THREADS];
|
||||
tlm_utils::multi_passthrough_initiator_socket<Arbiter, BUSWIDTH> iSocket;
|
||||
tlm_utils::multi_passthrough_target_socket<Arbiter, BUSWIDTH> 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<tlm_generic_payload*>());
|
||||
}
|
||||
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<tlm_generic_payload*>());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
tlm_utils::peq_with_cb_and_phase<Arbiter> payloadEventQueue;
|
||||
bool channelIsFree[NUMBER_OF_CHANNELS];
|
||||
|
||||
vector<bool> channelIsFree;
|
||||
|
||||
//used to account for the request_accept_delay in the dram controllers
|
||||
deque<tlm_generic_payload*> pendingRequests[NUMBER_OF_CHANNELS];
|
||||
// This is a queue of new transactions. The phase of a new request is BEGIN_REQ.
|
||||
vector<queue<tlm_generic_payload*>> pendingRequests;
|
||||
//used to account for the response_accept_delay in the initiators (traceplayer,core etc.)
|
||||
deque<tlm_generic_payload*> receivedResponses[NUMBER_OF_THREADS];
|
||||
// This is a queue of responses comming from the memory side. The phase of these transactions is BEGIN_RESP.
|
||||
vector<queue<tlm_generic_payload*>> 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);
|
||||
|
||||
@@ -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<Device>& 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<NumberOfTracePlayers, 128, NumberOfMemChannels>("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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<TracePlayer<>*> players;
|
||||
// All transactions pass through the same arbiter
|
||||
Arbiter<NumberOfTracePlayers, 128, NumberOfMemChannels> *arbiter;
|
||||
Arbiter<> *arbiter;
|
||||
// Each DRAM unit has a controller
|
||||
std::vector<Controller<>*> controllers;
|
||||
// TODO: Each DRAM has a reorder buffer (check this!)
|
||||
|
||||
@@ -162,12 +162,10 @@ void SimulationManager::startTraceAnalyzer()
|
||||
void SimulationManager::addTraceSetup(SimulationBatch& batch, tinyxml2::XMLElement* element)
|
||||
{
|
||||
vector<Device> 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());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user