Intensive refactor of DRAMSys project structure and CMakeFiles

This commit is contained in:
Thomas Psota
2022-12-08 15:05:23 +01:00
parent 2d8a5f66e4
commit b63c9beb50
709 changed files with 26751 additions and 1240 deletions

View File

@@ -0,0 +1,60 @@
# Copyright (c) 2020, Technische Universität 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:
# Matthias Jung
# Lukas Steiner
# Derek Christ
# Thomas Psota
########################################
### DRAMSys::simulator ###
########################################
project(DRAMSys_Simulator)
file(GLOB_RECURSE SOURCE_FILES CONFIGURE_DEPENDS *.cpp)
file(GLOB_RECURSE HEADER_FILES CONFIGURE_DEPENDS *.h;*.hpp)
add_executable(DRAMSys ${SOURCE_FILES} ${HEADER_FILES} )
target_include_directories(DRAMSys PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/../library/src/simulation/DRAMSysRecordable.cpp)
target_compile_definitions(DRAMSys PRIVATE RECORDING)
endif()
target_link_libraries(DRAMSys
PRIVATE
Threads::Threads
DRAMSys::libdramsys
)
build_source_group()
diagnostics_print(DRAMSys)

142
src/simulator/main.cpp Normal file
View File

@@ -0,0 +1,142 @@
/*
* Copyright (c) 2015, Technische Universität 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
* Luiza Correa
* Lukas Steiner
* Derek Christ
*/
#include <iostream>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <list>
#include <chrono>
#include <DRAMSys/config/DRAMSysConfiguration.h>
#include <memory>
#include <systemc>
#include <DRAMSys/simulation/DRAMSys.h>
#include <simulator/TraceSetup.h>
#include <simulator/TrafficInitiator.h>
#ifdef RECORDING
#include "simulation/DRAMSysRecordable.h"
#endif
using namespace sc_core;
std::string pathOfFile(const std::string &file)
{
return file.substr(0, file.find_last_of('/'));
}
int main(int argc, char **argv)
{
return sc_main(argc, argv);
}
int sc_main(int argc, char **argv)
{
sc_set_time_resolution(1, SC_PS);
std::string resources;
std::string simulationJson;
// Run only with default config (ddr3-example.json):
if (argc == 1)
{
// Get path of resources:
resources = pathOfFile(argv[0])
+ std::string("/../../DRAMSys/library/resources/");
simulationJson = resources + "simulations/ddr5-example.json";
}
// Run with specific config but default resource folders:
else if (argc == 2)
{
// Get path of resources:
resources = pathOfFile(argv[0])
+ std::string("/../../DRAMSys/library/resources/");
simulationJson = argv[1];
}
// Run with spefific config and specific resource folder:
else if (argc == 3)
{
simulationJson = argv[1];
resources = argv[2];
}
std::vector<std::unique_ptr<TrafficInitiator>> players;
DRAMSys::Config::Configuration configLib = DRAMSys::Config::from_path(simulationJson, resources);
// Instantiate DRAMSys:
std::unique_ptr<DRAMSys::DRAMSys> dramSys;
#ifdef RECORDING
if (configLib.simConfig.databaseRecording.value_or(false))
dramSys = std::make_unique<DRAMSysRecordable>("DRAMSys", configLib);
else
#endif
dramSys = std::make_unique<DRAMSys::DRAMSys>("DRAMSys", configLib);
if (!configLib.traceSetup.has_value())
SC_REPORT_FATAL("sc_main", "No tracesetup section provided.");
// Instantiate STL Players:
TraceSetup setup(dramSys->getConfig(), configLib.traceSetup.value(), resources, players);
// Bind STL Players with DRAMSys:
for (auto& player : players)
player->iSocket.bind(dramSys->tSocket);
// Store the starting of the simulation in wallclock time:
auto start = std::chrono::high_resolution_clock::now();
// Start SystemC Simulation:
sc_set_stop_mode(SC_STOP_FINISH_DELTA);
sc_start();
if (!sc_end_of_simulation_invoked())
{
SC_REPORT_WARNING("sc_main", "Simulation stopped without explicit sc_stop()");
sc_stop();
}
auto finish = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> elapsed = finish - start;
std::cout << "Simulation took " + std::to_string(elapsed.count()) + " seconds." << std::endl;
return 0;
}

View File

@@ -0,0 +1,238 @@
/*
* Copyright (c) 2016, Technische Universität 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:
* Eder F. Zulian
*/
#ifndef EXAMPLEINITIATOR_H
#define EXAMPLEINITIATOR_H
#include <cstdlib>
#include <iostream>
#include <systemc>
#include "MemoryManager.h"
#include "common/dramExtensions.h"
#include "TracePlayer.h"
struct ExampleInitiator : sc_core::sc_module
{
// TLM-2 socket, defaults to 32-bits wide, base protocol
tlm_utils::simple_initiator_socket<ExampleInitiator> socket;
SC_CTOR(ExampleInitiator)
: socket("socket"),
request_in_progress(nullptr),
m_peq(this, &ExampleInitiator::peq_cb)
{
socket.register_nb_transport_bw(this, &ExampleInitiator::nb_transport_bw);
SC_THREAD(thread_process);
}
void thread_process()
{
tlm::tlm_generic_payload *trans;
tlm::tlm_phase phase;
sc_core::sc_time delay;
dump_mem();
init_mem();
dump_mem();
for (unsigned char &i : data)
i = 0x55;
// Generate 2 write transactions
for (int i = 0; i < 2; i++) {
int adr = i * 64;
tlm::tlm_command cmd = tlm::TLM_WRITE_COMMAND;
// Grab a new transaction from the memory manager
trans = m_mm.allocate();
trans->acquire();
trans->set_command(cmd);
trans->set_address(adr);
trans->set_data_ptr(reinterpret_cast<unsigned char *>(&data[0]));
trans->set_data_length(64);
trans->set_streaming_width(4);
trans->set_byte_enable_ptr(nullptr);
trans->set_dmi_allowed(false);
trans->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
// ExampleInitiator must honor BEGIN_REQ/END_REQ exclusion rule
if (request_in_progress)
wait(end_request_event);
request_in_progress = trans;
phase = tlm::BEGIN_REQ;
// Timing annotation models processing time of initiator prior to call
delay = sc_core::sc_time(100000, sc_core::SC_PS);
std::cout << "Address " << std::hex << adr << " new, cmd=" << (cmd ? "write" : "read")
<< ", data=" << std::hex << data[0] << " at time " << sc_core::sc_time_stamp()
<< " in " << name() << std::endl;
GenerationExtension *genExtension = new GenerationExtension(sc_core::sc_time_stamp());
trans->set_auto_extension(genExtension);
// Non-blocking transport call on the forward path
tlm::tlm_sync_enum status;
status = socket->nb_transport_fw( *trans, phase, delay );
// Check value returned from nb_transport_fw
if (status == tlm::TLM_UPDATED) {
// The timing annotation must be honored
m_peq.notify( *trans, phase, delay );
} else if (status == tlm::TLM_COMPLETED) {
// The completion of the transaction necessarily ends the BEGIN_REQ phase
request_in_progress = nullptr;
// The target has terminated the transaction
check_transaction( *trans );
// Allow the memory manager to free the transaction object
trans->release();
}
sc_core::wait(sc_core::sc_time(500, sc_core::SC_NS));
dump_mem();
}
sc_core::wait(sc_core::sc_time(500, sc_core::SC_NS));
sc_core::sc_stop();
}
static void init_mem()
{
unsigned char buffer[64];
for (unsigned char &i : buffer)
i = 0xff;
for (int addr = 0; addr < 128; addr += 64) {
tlm::tlm_generic_payload trans;
trans.set_command( tlm::TLM_WRITE_COMMAND );
trans.set_address( addr );
trans.set_data_ptr( buffer );
trans.set_data_length( 64 );
socket->transport_dbg( trans );
}
}
static void dump_mem()
{
for (int addr = 0; addr < 128; addr += 64) {
unsigned char buffer[64];
tlm::tlm_generic_payload trans;
trans.set_command( tlm::TLM_READ_COMMAND );
trans.set_address( addr );
trans.set_data_ptr( buffer );
trans.set_data_length( 64 );
socket->transport_dbg( trans );
std::cout << "\nMemory dump\n";
for (int i = 0; i < 64; i++)
std::cout << "mem[" << addr + i << "] = " << std::hex << (int)buffer[i] << std::endl;
}
}
// TLM-2 backward non-blocking transport method
virtual tlm::tlm_sync_enum nb_transport_bw( tlm::tlm_generic_payload &trans,
tlm::tlm_phase &phase, sc_core::sc_time &delay )
{
m_peq.notify( trans, phase, delay );
return tlm::TLM_ACCEPTED;
}
// Payload event queue callback to handle transactions from target
// Transaction could have arrived through return path or backward path
void peq_cb(tlm::tlm_generic_payload &trans, const tlm::tlm_phase &phase)
{
if (phase == tlm::END_REQ || (&trans == request_in_progress
&& phase == tlm::BEGIN_RESP)) {
// The end of the BEGIN_REQ phase
request_in_progress = nullptr;
end_request_event.notify();
} else if (phase == tlm::BEGIN_REQ || phase == tlm::END_RESP)
SC_REPORT_FATAL("TLM-2", "Illegal transaction phase received by initiator");
if (phase == tlm::BEGIN_RESP) {
check_transaction( trans );
// Send final phase transition to target
tlm::tlm_phase fw_phase = tlm::END_RESP;
sc_core::sc_time delay = sc_core::sc_time(60000, sc_core::SC_PS);
socket->nb_transport_fw( trans, fw_phase, delay );
// Ignore return value
// Allow the memory manager to free the transaction object
trans.release();
}
}
// Called on receiving BEGIN_RESP or TLM_COMPLETED
void check_transaction(tlm::tlm_generic_payload &trans)
{
if ( trans.is_response_error() ) {
char txt[100];
sprintf(txt, "Transaction returned with error, response status = %s",
trans.get_response_string().c_str());
SC_REPORT_ERROR("TLM-2", txt);
}
tlm::tlm_command cmd = trans.get_command();
uint64_t adr = trans.get_address();
int *ptr = reinterpret_cast<int *>( trans.get_data_ptr() );
std::cout << std::hex << adr << " check, cmd=" << (cmd ? "write" : "read")
<< ", data=" << std::hex << *ptr << " at time " << sc_core::sc_time_stamp()
<< " in " << sc_core::name() << std::endl;
if (cmd == tlm::TLM_READ_COMMAND)
assert( *ptr == -int(adr) );
}
MemoryManager m_mm;
unsigned char data[64];
tlm::tlm_generic_payload *request_in_progress;
sc_core::sc_event end_request_event;
tlm_utils::peq_with_cb_and_phase<ExampleInitiator> m_peq;
};
#endif // EXAMPLEINITIATOR_H

View File

@@ -0,0 +1,238 @@
/*
* Copyright (c) 2022, Technische Universität 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 "LengthConverter.h"
using namespace sc_core;
using namespace tlm;
// TODO: return status, TLM_INCOMPLETE_RESPONSE, acquire + release
LengthConverter::LengthConverter(const sc_module_name &name, unsigned maxOutputLength, bool storageEnabled) :
sc_module(name), payloadEventQueue(this, &LengthConverter::peqCallback), storageEnabled(storageEnabled),
memoryManager(storageEnabled, maxOutputLength), maxOutputLength(maxOutputLength)
{
iSocket.register_nb_transport_bw(this, &LengthConverter::nb_transport_bw);
tSocket.register_nb_transport_fw(this, &LengthConverter::nb_transport_fw);
tSocket.register_transport_dbg(this, &LengthConverter::transport_dbg);
}
tlm_sync_enum LengthConverter::nb_transport_fw(tlm_generic_payload& trans,
tlm_phase& phase, sc_time& fwDelay)
{
if (phase == BEGIN_REQ)
trans.acquire();
payloadEventQueue.notify(trans, phase, fwDelay);
return TLM_ACCEPTED;
}
tlm_sync_enum LengthConverter::nb_transport_bw(tlm_generic_payload &payload,
tlm_phase &phase, sc_time &bwDelay)
{
payloadEventQueue.notify(payload, phase, bwDelay);
return TLM_ACCEPTED;
}
unsigned int LengthConverter::transport_dbg(tlm_generic_payload &trans)
{
return iSocket->transport_dbg(trans);
}
void LengthConverter::peqCallback(tlm_generic_payload &cbTrans, const tlm_phase &cbPhase)
{
if (cbPhase == BEGIN_REQ) // from initiator
{
if (cbTrans.get_data_length() <= maxOutputLength)
{
// pipe transaction through
tlm_phase fwPhase = BEGIN_REQ;
sc_time fwDelay = SC_ZERO_TIME;
tlm_sync_enum returnStatus = iSocket->nb_transport_fw(cbTrans, fwPhase, fwDelay);
// TODO: END_REQ/BEGIN_RESP shortcut
}
else
{
// split transaction up into multiple sub-transactions
createChildTranses(&cbTrans);
tlm_generic_payload* firstChildTrans = cbTrans.get_extension<ParentExtension>()->getNextChildTrans();
tlm_phase fwPhase = BEGIN_REQ;
sc_time fwDelay = SC_ZERO_TIME;
tlm_sync_enum returnStatus = iSocket->nb_transport_fw(*firstChildTrans, fwPhase, fwDelay);
}
}
else if (cbPhase == END_REQ)
{
if (ChildExtension::isChildTrans(&cbTrans))
{
tlm_generic_payload* nextChildTrans = cbTrans.get_extension<ChildExtension>()->getNextChildTrans();
if (nextChildTrans != nullptr)
{
tlm_phase fwPhase = BEGIN_REQ;
//sc_time fwDelay = SC_ZERO_TIME;
sc_time fwDelay = sc_time(1, SC_NS);
tlm_sync_enum returnStatus = iSocket->nb_transport_fw(*nextChildTrans, fwPhase, fwDelay);
}
else
{
tlm_generic_payload* parentTrans = cbTrans.get_extension<ChildExtension>()->getParentTrans();
tlm_phase bwPhase = END_REQ;
sc_time bwDelay = SC_ZERO_TIME;
tlm_sync_enum returnStatus = tSocket->nb_transport_bw(*parentTrans, bwPhase, bwDelay);
}
}
else
{
tlm_phase bwPhase = END_REQ;
sc_time bwDelay = SC_ZERO_TIME;
tlm_sync_enum returnStatus = tSocket->nb_transport_bw(cbTrans, bwPhase, bwDelay);
}
}
else if (cbPhase == BEGIN_RESP)
{
if (ChildExtension::isChildTrans(&cbTrans))
{
{
tlm_phase fwPhase = END_RESP;
sc_time fwDelay = SC_ZERO_TIME;
tlm_sync_enum returnStatus = iSocket->nb_transport_fw(cbTrans, fwPhase, fwDelay);
}
if (storageEnabled && cbTrans.is_read())
{
tlm_generic_payload* parentTrans = cbTrans.get_extension<ChildExtension>()->getParentTrans();
std::copy(cbTrans.get_data_ptr(), cbTrans.get_data_ptr() + maxOutputLength,
parentTrans->get_data_ptr() + (cbTrans.get_address() - parentTrans->get_address()));
}
if (cbTrans.get_extension<ChildExtension>()->notifyChildTransCompletion()) // all children finished
{
// BEGIN_RESP über tSocket
tlm_generic_payload* parentTrans = cbTrans.get_extension<ChildExtension>()->getParentTrans();
tlm_phase bwPhase = BEGIN_RESP;
sc_time bwDelay = SC_ZERO_TIME;
parentTrans->set_response_status(tlm::TLM_OK_RESPONSE);
tlm_sync_enum returnStatus = tSocket->nb_transport_bw(*parentTrans, bwPhase, bwDelay);
}
}
else
{
tlm_phase bwPhase = BEGIN_RESP;
sc_time bwDelay = SC_ZERO_TIME;
cbTrans.set_response_status(tlm::TLM_OK_RESPONSE);
tlm_sync_enum returnStatus = tSocket->nb_transport_bw(cbTrans, bwPhase, bwDelay);
}
}
else if (cbPhase == END_RESP)
{
if (ParentExtension::isParentTrans(&cbTrans))
{
cbTrans.get_extension<ParentExtension>()->releaseChildTranses();
}
else
{
tlm_phase fwPhase = END_RESP;
sc_time fwDelay = SC_ZERO_TIME;
tlm_sync_enum returnStatus = iSocket->nb_transport_fw(cbTrans, fwPhase, fwDelay);
}
cbTrans.release();
}
else
SC_REPORT_FATAL(0, "Payload event queue in LengthConverter was triggered with unknown phase");
}
void LengthConverter::createChildTranses(tlm_generic_payload* parentTrans)
{
unsigned numChildTranses = parentTrans->get_data_length() / maxOutputLength;
std::vector<tlm_generic_payload*> childTranses;
for (unsigned childId = 0; childId < numChildTranses; childId++)
{
tlm_generic_payload* childTrans = memoryManager.allocate();
childTrans->acquire();
childTrans->set_command(parentTrans->get_command());
childTrans->set_address(parentTrans->get_address() + childId * maxOutputLength);
childTrans->set_data_length(maxOutputLength);
if (storageEnabled && parentTrans->is_write())
std::copy(parentTrans->get_data_ptr() + childId * maxOutputLength, parentTrans->get_data_ptr() +
(childId + 1) * maxOutputLength, childTrans->get_data_ptr());
ChildExtension::setExtension(childTrans, parentTrans);
childTranses.push_back(childTrans);
}
ParentExtension::setExtension(parentTrans, std::move(childTranses));
}
LengthConverter::MemoryManager::MemoryManager(bool storageEnabled, unsigned maxDataLength)
: storageEnabled(storageEnabled), maxDataLength(maxDataLength)
{}
LengthConverter::MemoryManager::~MemoryManager()
{
while (!freePayloads.empty())
{
tlm_generic_payload* payload = freePayloads.top();
if (storageEnabled)
delete[] payload->get_data_ptr();
payload->reset();
delete payload;
freePayloads.pop();
}
}
tlm_generic_payload* LengthConverter::MemoryManager::allocate()
{
if (freePayloads.empty())
{
auto* payload = new tlm_generic_payload(this);
if (storageEnabled)
{
auto* data = new unsigned char[maxDataLength];
payload->set_data_ptr(data);
}
return payload;
}
else
{
tlm_generic_payload* result = freePayloads.top();
freePayloads.pop();
return result;
}
}
void LengthConverter::MemoryManager::free(tlm_generic_payload* payload)
{
freePayloads.push(payload);
}

View File

@@ -0,0 +1,233 @@
/*
* Copyright (c) 2022, Technische Universität 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 LENGTHCONVERTER_H
#define LENGTHCONVERTER_H
#include <iostream>
#include <utility>
#include <vector>
#include <queue>
#include <set>
#include <unordered_map>
#include <stack>
#include <tlm>
#include <systemc>
#include <tlm_utils/simple_initiator_socket.h>
#include <tlm_utils/simple_target_socket.h>
#include <tlm_utils/peq_with_cb_and_phase.h>
//TLM_DECLARE_EXTENDED_PHASE(REQ_ARBITRATION);
//TLM_DECLARE_EXTENDED_PHASE(RESP_ARBITRATION);
class LengthConverter : public sc_core::sc_module
{
public:
tlm_utils::simple_initiator_socket<LengthConverter> iSocket;
tlm_utils::simple_target_socket<LengthConverter> tSocket;
LengthConverter(const sc_core::sc_module_name& name, unsigned maxOutputLength, bool storageEnabled);
SC_HAS_PROCESS(LengthConverter);
private:
tlm_utils::peq_with_cb_and_phase<LengthConverter> payloadEventQueue;
void peqCallback(tlm::tlm_generic_payload &payload, const tlm::tlm_phase &phase);
//std::vector<bool> tSocketIsBusy;
//std::vector<bool> iSocketIsBusy;
const unsigned maxOutputLength;
const bool storageEnabled;
void createChildTranses(tlm::tlm_generic_payload* parentTrans);
//std::uint64_t getTargetAddress(std::uint64_t address) const;
//int getISocketId(std::uint64_t address) const;
//std::vector<std::queue<tlm::tlm_generic_payload *>> pendingRequests;
tlm::tlm_sync_enum nb_transport_fw(tlm::tlm_generic_payload &trans, tlm::tlm_phase &phase,
sc_core::sc_time &fwDelay);
tlm::tlm_sync_enum nb_transport_bw(tlm::tlm_generic_payload &payload, tlm::tlm_phase &phase,
sc_core::sc_time &bwDelay);
unsigned int transport_dbg(tlm::tlm_generic_payload &trans);
class MemoryManager : public tlm::tlm_mm_interface
{
public:
MemoryManager(bool storageEnabled, unsigned maxDataLength);
~MemoryManager() override;
tlm::tlm_generic_payload* allocate();
void free(tlm::tlm_generic_payload* payload) override;
private:
std::stack<tlm::tlm_generic_payload*> freePayloads;
bool storageEnabled = false;
unsigned maxDataLength;
} memoryManager;
class ChildExtension : public tlm::tlm_extension<ChildExtension>
{
private:
tlm::tlm_generic_payload* parentTrans;
explicit ChildExtension(tlm::tlm_generic_payload* parentTrans) : parentTrans(parentTrans) {}
public:
//ChildExtension() = delete;
tlm_extension_base* clone() const override
{
return new ChildExtension(parentTrans);
}
void copy_from(tlm_extension_base const &ext) override
{
const auto& cpyFrom = dynamic_cast<const ChildExtension&>(ext);
parentTrans = cpyFrom.parentTrans;
}
tlm::tlm_generic_payload* getParentTrans()
{
return parentTrans;
}
static void setExtension(tlm::tlm_generic_payload* childTrans, tlm::tlm_generic_payload* parentTrans)
{
auto *extension = childTrans->get_extension<ChildExtension>();
if (extension != nullptr)
{
extension->parentTrans = parentTrans;
}
else
{
extension = new ChildExtension(parentTrans);
childTrans->set_auto_extension(extension);
}
}
static bool isChildTrans(const tlm::tlm_generic_payload* trans)
{
if (trans->get_extension<ChildExtension>() != nullptr)
return true;
else
return false;
}
tlm::tlm_generic_payload* getNextChildTrans()
{
return parentTrans->get_extension<ParentExtension>()->getNextChildTrans();
}
bool notifyChildTransCompletion()
{
return parentTrans->get_extension<ParentExtension>()->notifyChildTransCompletion();
}
};
class ParentExtension : public tlm::tlm_extension<ParentExtension>
{
private:
std::vector<tlm::tlm_generic_payload*> childTranses;
unsigned nextEndReqChildId = 0;
unsigned completedChildTranses = 0;
explicit ParentExtension(std::vector<tlm::tlm_generic_payload*> _childTranses)
: childTranses(std::move(_childTranses)) {}
public:
ParentExtension() = delete;
tlm_extension_base* clone() const override
{
return new ParentExtension(childTranses);
}
void copy_from(tlm_extension_base const &ext) override
{
const auto& cpyFrom = dynamic_cast<const ParentExtension&>(ext);
childTranses = cpyFrom.childTranses;
}
static bool isParentTrans(const tlm::tlm_generic_payload* trans)
{
auto* extension = trans->get_extension<ParentExtension>();
if (extension != nullptr)
return !extension->childTranses.empty();
else
return false;
}
static void setExtension(tlm::tlm_generic_payload* parentTrans, std::vector<tlm::tlm_generic_payload*> childTranses)
{
auto* extension = parentTrans->get_extension<ParentExtension>();
if (extension != nullptr)
{
extension->childTranses = std::move(childTranses);
extension->nextEndReqChildId = 0;
extension->completedChildTranses = 0;
}
else
{
extension = new ParentExtension(std::move(childTranses));
parentTrans->set_auto_extension(extension);
}
}
tlm::tlm_generic_payload* getNextChildTrans()
{
if (nextEndReqChildId < childTranses.size())
return childTranses[nextEndReqChildId++];
else
return nullptr;
}
bool notifyChildTransCompletion()
{
completedChildTranses++;
return completedChildTranses == childTranses.size();
}
void releaseChildTranses()
{
std::for_each(childTranses.begin(), childTranses.end(),
[](tlm::tlm_generic_payload* childTrans){childTrans->release();});
childTranses.clear();
}
};
};
#endif // LENGTHCONVERTER_H

View File

@@ -0,0 +1,98 @@
/*
* Copyright (c) 2015, Technische Universität 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
*/
#include "MemoryManager.h"
#include <DRAMSys/common/DebugManager.h>
#include <DRAMSys/configuration/Configuration.h>
using namespace tlm;
MemoryManager::MemoryManager(bool storageEnabled)
: numberOfAllocations(0), numberOfFrees(0), storageEnabled(storageEnabled)
{}
MemoryManager::~MemoryManager()
{
for (auto& innerBuffer : freePayloads)
{
while (!innerBuffer.second.empty())
{
tlm_generic_payload* payload = innerBuffer.second.top();
if (storageEnabled)
delete[] payload->get_data_ptr();
payload->reset();
delete payload;
innerBuffer.second.pop();
numberOfFrees++;
}
}
// Comment in if you are suspecting a memory leak in the manager
//PRINTDEBUGMESSAGE("MemoryManager","Number of allocated payloads: " + to_string(numberOfAllocations));
//PRINTDEBUGMESSAGE("MemoryManager","Number of freed payloads: " + to_string(numberOfFrees));
}
tlm_generic_payload& MemoryManager::allocate(unsigned dataLength)
{
if (freePayloads[dataLength].empty())
{
numberOfAllocations++;
auto* payload = new tlm_generic_payload(this);
if (storageEnabled)
{
// Allocate a data buffer and initialize it with zeroes:
auto* data = new unsigned char[dataLength];
std::fill(data, data + dataLength, 0);
payload->set_data_ptr(data);
}
return *payload;
}
else
{
tlm_generic_payload* result = freePayloads[dataLength].top();
freePayloads[dataLength].pop();
return *result;
}
}
void MemoryManager::free(tlm_generic_payload* payload)
{
unsigned dataLength = payload->get_data_length();
freePayloads[dataLength].push(payload);
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) 2015, Technische Universität 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
*/
#ifndef MEMORYMANAGER_H
#define MEMORYMANAGER_H
#include <unordered_map>
#include <stack>
#include <tlm>
class MemoryManager : public tlm::tlm_mm_interface
{
public:
MemoryManager(bool storageEnabled);
~MemoryManager() override;
tlm::tlm_generic_payload& allocate(unsigned dataLength);
void free(tlm::tlm_generic_payload* payload) override;
private:
uint64_t numberOfAllocations;
uint64_t numberOfFrees;
std::unordered_map<unsigned, std::stack<tlm::tlm_generic_payload*>> freePayloads;
bool storageEnabled = false;
};
#endif // MEMORYMANAGER_H

View File

@@ -0,0 +1,236 @@
/*
* Copyright (c) 2015, Technische Universität 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
* Éder F. Zulian
* Felipe S. Prado
* Derek Christ
*/
#include "StlPlayer.h"
using namespace sc_core;
using namespace tlm;
StlPlayer::StlPlayer(const sc_module_name &name, const Configuration& config, const std::string &pathToTrace,
const sc_time &playerClk, unsigned int maxPendingReadRequests, unsigned int maxPendingWriteRequests,
TraceSetup& setup, bool relative) :
TrafficInitiator(name, config, setup, maxPendingReadRequests, maxPendingWriteRequests,
config.memSpec->defaultBytesPerBurst),
file(pathToTrace), relative(relative), playerClk(playerClk)
{
currentBuffer = &lineContents[0];
parseBuffer = &lineContents[1];
if (!file.is_open())
SC_REPORT_FATAL("StlPlayer", (std::string("Could not open trace ") + pathToTrace).c_str());
else
{
std::string line;
while (std::getline(file, line))
{
if (line.size() > 1 && line[0] != '#')
numberOfLines++;
}
file.clear();
file.seekg(0);
if (numberOfLines == 0)
SC_REPORT_FATAL("StlPlayer", "Trace file is empty");
}
currentBuffer->reserve(lineBufferSize);
parseBuffer->reserve(lineBufferSize);
parseTraceFile();
lineIterator = currentBuffer->cend();
}
StlPlayer::~StlPlayer()
{
if (parserThread.joinable())
parserThread.join();
}
void StlPlayer::sendNextPayload()
{
if (lineIterator == currentBuffer->cend())
{
lineIterator = swapBuffers();
if (lineIterator == currentBuffer->cend())
{
// The file is empty. Nothing more to do.
finished = true;
return;
}
}
// Allocate a generic payload for this request.
tlm_generic_payload& payload = setup.allocatePayload(lineIterator->dataLength);
payload.acquire();
// Fill up the payload.
payload.set_address(lineIterator->address);
payload.set_response_status(TLM_INCOMPLETE_RESPONSE);
payload.set_dmi_allowed(false);
payload.set_byte_enable_length(0);
payload.set_data_length(lineIterator->dataLength);
payload.set_command(lineIterator->command);
std::copy(lineIterator->data.begin(), lineIterator->data.end(), payload.get_data_ptr());
sc_time sendingTime;
sc_time sendingOffset;
if (transactionsSent == 0)
sendingOffset = SC_ZERO_TIME;
else
sendingOffset = playerClk - (sc_time_stamp() % playerClk);
if (!relative)
sendingTime = std::max(sc_time_stamp() + sendingOffset, lineIterator->sendingTime);
else
sendingTime = sc_time_stamp() + sendingOffset + lineIterator->sendingTime;
sendToTarget(payload, BEGIN_REQ, sendingTime - sc_time_stamp());
transactionsSent++;
if (payload.get_command() == tlm::TLM_READ_COMMAND)
pendingReadRequests++;
else if (payload.get_command() == tlm::TLM_WRITE_COMMAND)
pendingWriteRequests++;
PRINTDEBUGMESSAGE(name(), "Performing request #" + std::to_string(transactionsSent));
lineIterator++;
}
void StlPlayer::parseTraceFile()
{
unsigned parsedLines = 0;
parseBuffer->clear();
while (file && !file.eof() && parsedLines < lineBufferSize)
{
// Get a new line from the input file.
std::string line;
std::getline(file, line);
lineCnt++;
// If the line is empty (\n or \r\n) or starts with '#' (comment) the transaction is ignored.
if (line.size() <= 1 || line.at(0) == '#')
continue;
parsedLines++;
parseBuffer->emplace_back();
LineContent &content = parseBuffer->back();
// Trace files MUST provide timestamp, command and address for every
// transaction. The data information depends on the storage mode
// configuration.
std::string element;
std::istringstream iss;
iss.str(line);
// Get the timestamp for the transaction.
iss >> element;
if (element.empty())
SC_REPORT_FATAL("StlPlayer", ("Malformed trace file line " + std::to_string(lineCnt) + ".").c_str());
content.sendingTime = playerClk * static_cast<double>(std::stoull(element));
// Get the optional burst length and command
iss >> element;
if (element.empty())
SC_REPORT_FATAL("StlPlayer", ("Malformed trace file line " + std::to_string(lineCnt) + ".").c_str());
if (element.at(0) == '(')
{
element.erase(0, 1);
content.dataLength = std::stoul(element);
iss >> element;
if (element.empty())
SC_REPORT_FATAL("StlPlayer", ("Malformed trace file line " + std::to_string(lineCnt) + ".").c_str());
}
else
content.dataLength = defaultDataLength;
if (element == "read")
content.command = TLM_READ_COMMAND;
else if (element == "write")
content.command = TLM_WRITE_COMMAND;
else
SC_REPORT_FATAL("StlPlayer", ("Malformed trace file line " + std::to_string(lineCnt) + ".").c_str());
// Get the address.
iss >> element;
if (element.empty())
SC_REPORT_FATAL("StlPlayer", ("Malformed trace file line " + std::to_string(lineCnt) + ".").c_str());
content.address = std::stoull(element, nullptr, 16);
// Get the data if necessary.
if (storageEnabled && content.command == TLM_WRITE_COMMAND)
{
// The input trace file must provide the data to be stored into the memory.
iss >> element;
// Check if data length in the trace file is correct.
// We need two characters to represent 1 byte in hexadecimal. Offset for 0x prefix.
if (element.length() != (content.dataLength * 2 + 2))
SC_REPORT_FATAL("StlPlayer", ("Malformed trace file line " + std::to_string(lineCnt) + ".").c_str());
// Set data
for (unsigned i = 0; i < content.dataLength; i++)
content.data.emplace_back(static_cast<unsigned char>
(std::stoi(element.substr(i * 2 + 2, 2), nullptr, 16)));
}
}
}
std::vector<LineContent>::const_iterator StlPlayer::swapBuffers()
{
// Wait for parser to finish
if (parserThread.joinable())
parserThread.join();
// Swap buffers
std::swap(currentBuffer, parseBuffer);
// Start new parser thread
parserThread = std::thread(&StlPlayer::parseTraceFile, this);
return currentBuffer->cbegin();
}
uint64_t StlPlayer::getNumberOfLines() const
{
return numberOfLines;
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright (c) 2015, Technische Universität 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
* Éder F. Zulian
* Felipe S. Prado
* Derek Christ
*/
#ifndef STLPLAYER_H
#define STLPLAYER_H
#include <sstream>
#include <vector>
#include <array>
#include <thread>
#include <fstream>
#include <systemc>
#include <tlm>
#include "TraceSetup.h"
#include "TrafficInitiator.h"
struct LineContent
{
sc_core::sc_time sendingTime;
unsigned dataLength;
tlm::tlm_command command;
uint64_t address;
std::vector<unsigned char> data;
};
class StlPlayer : public TrafficInitiator
{
public:
StlPlayer(const sc_core::sc_module_name &name,
const Configuration& config,
const std::string &pathToTrace,
const sc_core::sc_time &playerClk,
unsigned int maxPendingReadRequests,
unsigned int maxPendingWriteRequests,
TraceSetup& setup,
bool relative);
~StlPlayer() override;
void sendNextPayload() override;
uint64_t getNumberOfLines() const;
private:
void parseTraceFile();
std::vector<LineContent>::const_iterator swapBuffers();
std::ifstream file;
uint64_t lineCnt = 0;
uint64_t numberOfLines = 0;
const sc_core::sc_time playerClk; // May be different from the memory clock!
static constexpr unsigned lineBufferSize = 10000;
std::vector<LineContent>* currentBuffer;
std::vector<LineContent>* parseBuffer;
std::array<std::vector<LineContent>, 2> lineContents;
std::vector<LineContent>::const_iterator lineIterator;
std::thread parserThread;
const bool relative;
};
#endif // STLPLAYER_H

View File

@@ -0,0 +1,235 @@
/*
* Copyright (c) 2017, Technische Universität 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:
* Matthias Jung
* Luiza Correa
* Derek Christ
*/
#include "TraceSetup.h"
#include "StlPlayer.h"
#include "TrafficGenerator.h"
#include <algorithm>
#include <iomanip>
#include <map>
using namespace sc_core;
using namespace tlm;
TraceSetup::TraceSetup(const Configuration& config,
const DRAMSys::Config::TraceSetup& traceSetup,
const std::string& pathToResources,
std::vector<std::unique_ptr<TrafficInitiator>>& players)
: memoryManager(config.storeMode != Configuration::StoreMode::NoStorage)
{
if (traceSetup.initiators.empty())
SC_REPORT_FATAL("TraceSetup", "No traffic initiators specified");
for (const auto &initiator : traceSetup.initiators)
{
std::visit(
[&](auto &&initiator)
{
std::string name = initiator.name;
double frequencyMHz = initiator.clkMhz;
sc_time playerClk = sc_time(1.0 / frequencyMHz, SC_US);
unsigned int maxPendingReadRequests = [=]() -> unsigned int
{
if (const auto &maxPendingReadRequests = initiator.maxPendingReadRequests)
return *maxPendingReadRequests;
else
return 0;
}();
unsigned int maxPendingWriteRequests = [=]() -> unsigned int
{
if (const auto &maxPendingWriteRequests = initiator.maxPendingWriteRequests)
return *maxPendingWriteRequests;
else
return 0;
}();
using T = std::decay_t<decltype(initiator)>;
if constexpr (std::is_same_v<T, DRAMSys::Config::TracePlayer>)
{
size_t pos = name.rfind('.');
if (pos == std::string::npos)
throw std::runtime_error("Name of the trace file does not contain a valid extension.");
// Get the extension and make it lower case
std::string ext = name.substr(pos + 1);
std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
std::stringstream stlFileStream;
stlFileStream << pathToResources << "/traces/" << name;
std::string stlFile = stlFileStream.str();
std::string moduleName = name;
// replace all '.' to '_'
std::replace(moduleName.begin(), moduleName.end(), '.', '_');
StlPlayer *player;
if (ext == "stl")
player = new StlPlayer(moduleName.c_str(), config, stlFile, playerClk, maxPendingReadRequests,
maxPendingWriteRequests, *this, false);
else if (ext == "rstl")
player = new StlPlayer(moduleName.c_str(), config, stlFile, playerClk, maxPendingReadRequests,
maxPendingWriteRequests, *this, true);
else
throw std::runtime_error("Unsupported file extension in " + name);
players.push_back(std::unique_ptr<TrafficInitiator>(player));
totalTransactions += player->getNumberOfLines();
}
else if constexpr (std::is_same_v<T, DRAMSys::Config::TraceGenerator>)
{
TrafficGenerator *trafficGenerator = new TrafficGenerator(name.c_str(), config, initiator, *this);
players.push_back(std::unique_ptr<TrafficInitiator>(trafficGenerator));
totalTransactions += trafficGenerator->getTotalTransactions();
}
else // if constexpr (std::is_same_v<T, DRAMSys::Config::TraceHammer>)
{
uint64_t numRequests = initiator.numRequests;
uint64_t rowIncrement = initiator.rowIncrement;
players.push_back(
std::unique_ptr<TrafficInitiator>(new TrafficGeneratorHammer(name.c_str(), config, initiator, *this)));
totalTransactions += numRequests;
}
},
initiator);
}
for (const auto &inititatorConf : traceSetup.initiators)
{
if (auto generatorConf = std::get_if<DRAMSys::Config::TraceGenerator>(&inititatorConf))
{
if (const auto &idleUntil = generatorConf->idleUntil)
{
const std::string name = generatorConf->name;
auto listenerIt = std::find_if(players.begin(), players.end(),
[&name](const std::unique_ptr<TrafficInitiator> &initiator)
{ return initiator->name() == name; });
// Should be found
auto listener = dynamic_cast<TrafficGenerator *>(listenerIt->get());
auto notifierIt =
std::find_if(players.begin(), players.end(),
[&idleUntil](const std::unique_ptr<TrafficInitiator> &initiator)
{
if (auto generator = dynamic_cast<const TrafficGenerator *>(initiator.get()))
{
if (generator->hasStateTransitionEvent(*idleUntil))
return true;
}
return false;
});
if (notifierIt == players.end())
SC_REPORT_FATAL("TraceSetup", "Event to listen on not found.");
auto notifier = dynamic_cast<TrafficGenerator *>(notifierIt->get());
listener->waitUntil(&notifier->getStateTransitionEvent(*idleUntil));
}
}
}
remainingTransactions = totalTransactions;
numberOfTrafficInitiators = players.size();
defaultDataLength = config.memSpec->defaultBytesPerBurst;
}
void TraceSetup::trafficInitiatorTerminates()
{
finishedTrafficInitiators++;
if (finishedTrafficInitiators == numberOfTrafficInitiators)
sc_stop();
}
void TraceSetup::transactionFinished()
{
remainingTransactions--;
loadBar(totalTransactions - remainingTransactions, totalTransactions);
if (remainingTransactions == 0)
std::cout << std::endl;
}
tlm_generic_payload& TraceSetup::allocatePayload(unsigned dataLength)
{
return memoryManager.allocate(dataLength);
}
tlm_generic_payload& TraceSetup::allocatePayload()
{
return allocatePayload(defaultDataLength);
}
void TraceSetup::loadBar(uint64_t x, uint64_t n, unsigned int w, unsigned int granularity)
{
if ((n < 100) || ((x != n) && (x % (n / 100 * granularity) != 0)))
return;
float ratio = x / (float)n;
unsigned int c = (ratio * w);
float rest = (ratio * w) - c;
std::cout << std::setw(3) << round(ratio * 100) << "% |";
for (unsigned int x = 0; x < c; x++)
std::cout << "";
if (rest >= 0 && rest < 0.125f && c != w)
std::cout << " ";
if (rest >= 0.125f && rest < 2 * 0.125f)
std::cout << "";
if (rest >= 2 * 0.125f && rest < 3 * 0.125f)
std::cout << "";
if (rest >= 3 * 0.125f && rest < 4 * 0.125f)
std::cout << "";
if (rest >= 4 * 0.125f && rest < 5 * 0.125f)
std::cout << "";
if (rest >= 5 * 0.125f && rest < 6 * 0.125f)
std::cout << "";
if (rest >= 6 * 0.125f && rest < 7 * 0.125f)
std::cout << "";
if (rest >= 7 * 0.125f && rest < 8 * 0.125f)
std::cout << "";
for (unsigned int x = c; x < (w - 1); x++)
std::cout << " ";
std::cout << "|\r" << std::flush;
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright (c) 2017, Technische Universität 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:
* Matthias Jung
* Derek Christ
*/
#ifndef TRACESETUP_H
#define TRACESETUP_H
#include <DRAMSys/config/DRAMSysConfiguration.h>
#include <DRAMSys/configuration/Configuration.h>
#include <vector>
#include <string>
#include <memory>
#include <tlm>
#include "MemoryManager.h"
class TrafficInitiator;
class TraceSetup
{
public:
TraceSetup(const Configuration& config,
const DRAMSys::Config::TraceSetup &traceSetup,
const std::string &pathToResources,
std::vector<std::unique_ptr<TrafficInitiator>> &devices);
void trafficInitiatorTerminates();
void transactionFinished();
tlm::tlm_generic_payload& allocatePayload(unsigned dataLength);
tlm::tlm_generic_payload& allocatePayload();
private:
unsigned int numberOfTrafficInitiators;
uint64_t totalTransactions = 0;
uint64_t remainingTransactions;
unsigned int finishedTrafficInitiators = 0;
MemoryManager memoryManager;
unsigned defaultDataLength = 64;
static void loadBar(uint64_t x, uint64_t n, unsigned int w = 50, unsigned int granularity = 1);
};
#endif // TRACESETUP_H

View File

@@ -0,0 +1,411 @@
/*
* Copyright (c) 2015, Technische Universität 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
* Derek Christ
*/
#include "TrafficGenerator.h"
#include "TraceSetup.h"
#include <limits>
using namespace sc_core;
using namespace tlm;
TrafficGeneratorIf::TrafficGeneratorIf(const sc_core::sc_module_name& name, const Configuration& config,
TraceSetup& setup,
unsigned int maxPendingReadRequests, unsigned int maxPendingWriteRequests,
unsigned int dataLength)
: TrafficInitiator(name, config, setup, maxPendingReadRequests, maxPendingWriteRequests, dataLength)
{
}
void TrafficGeneratorIf::sendNextPayload()
{
prepareNextPayload();
if (finished)
return;
// TODO: column / burst breite
uint64_t address = getNextAddress();
tlm_command command = getNextCommand();
if (command == tlm::TLM_READ_COMMAND)
pendingReadRequests++;
else if (command == tlm::TLM_WRITE_COMMAND)
pendingWriteRequests++;
tlm_generic_payload& payload = setup.allocatePayload();
payload.acquire();
payload.set_address(address);
payload.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
payload.set_dmi_allowed(false);
payload.set_byte_enable_length(0);
payload.set_data_length(defaultDataLength);
payload.set_command(command);
sc_time generatorClk = getGeneratorClk();
sc_time sendingOffset;
if (transactionsSent == 0)
sendingOffset = SC_ZERO_TIME + generatorClk * clksToIdle();
else
sendingOffset = (generatorClk * clksPerRequest()) - (sc_time_stamp() % generatorClk) + generatorClk * clksToIdle();
// TODO: do not send two requests in the same cycle
sendToTarget(payload, tlm::BEGIN_REQ, sendingOffset);
transactionsSent++;
PRINTDEBUGMESSAGE(name(), "Performing request #" + std::to_string(transactionsSent));
payloadSent();
}
TrafficGenerator::TrafficGenerator(const sc_module_name& name, const Configuration& config,
const DRAMSys::Config::TraceGenerator& conf, TraceSetup& setup)
: TrafficGeneratorIf(name, config, setup, conf.maxPendingReadRequests.value_or(defaultMaxPendingReadRequests),
conf.maxPendingWriteRequests.value_or(defaultMaxPendingWriteRequests),
conf.dataLength.value_or(config.memSpec->defaultBytesPerBurst)),
generatorClk(TrafficInitiator::evaluateGeneratorClk(conf)), conf(conf),
maxTransactions(conf.maxTransactions.value_or(std::numeric_limits<uint64_t>::max())),
simMemSizeInBytes(config.memSpec->getSimMemSizeInBytes()),
randomGenerator(std::default_random_engine(conf.seed.value_or(defaultSeed)))
{
// Perform checks for all states
for (const auto &state : conf.states)
{
if (auto trafficState = std::get_if<DRAMSys::Config::TraceGeneratorTrafficState>(&state.second))
{
uint64_t minAddress = evaluateMinAddress(*trafficState);
uint64_t maxAddress = evaluateMaxAddress(*trafficState, simMemSizeInBytes);
double rwRatio = (*trafficState).rwRatio;
if (minAddress > config.memSpec->getSimMemSizeInBytes() - 1)
SC_REPORT_FATAL("TrafficGenerator", "minAddress is out of range.");
if (maxAddress > config.memSpec->getSimMemSizeInBytes() - 1)
SC_REPORT_FATAL("TrafficGenerator", "minAddress is out of range.");
if (maxAddress < minAddress)
SC_REPORT_FATAL("TrafficGenerator", "maxAddress is smaller than minAddress.");
if (rwRatio < 0 || rwRatio > 1)
SC_REPORT_FATAL("TraceSetup", "Read/Write ratio is not a number between 0 and 1.");
if (const auto &eventName = trafficState->notify)
{
stateTranstitionEvents.emplace(std::piecewise_construct, std::forward_as_tuple(*eventName),
std::forward_as_tuple(eventName->c_str(), state.first));
}
}
}
if (auto trafficState =
std::get_if<DRAMSys::Config::TraceGeneratorTrafficState>(&conf.states.at(currentState)))
{
uint64_t minAddress = evaluateMinAddress(*trafficState);
uint64_t maxAddress = evaluateMaxAddress(*trafficState, simMemSizeInBytes);
randomAddressDistribution = std::uniform_int_distribution<uint64_t>(minAddress, maxAddress);
currentClksPerRequest = trafficState->clksPerRequest.value_or(defaultClksPerRequest);
}
calculateTransitions();
}
void TrafficGenerator::calculateTransitions()
{
unsigned int state = 0;
uint64_t totalTransactions = 0;
stateSequence.push_back(state);
while (true)
{
auto transitionsIt = conf.transitions.equal_range(state);
float probabilityAccumulated = 0.0f;
std::map<unsigned int, std::pair<float, float>> transitionsDistribution;
for (auto it = transitionsIt.first; it != transitionsIt.second; ++it)
{
float lowerLimit = probabilityAccumulated;
probabilityAccumulated += it->second.probability;
float upperLimit = probabilityAccumulated;
transitionsDistribution[it->second.to] = {lowerLimit, upperLimit};
}
if (probabilityAccumulated > 1.001f)
SC_REPORT_WARNING("TrafficGenerator", "Sum of transition probabilities greater than 1.");
float random = randomDistribution(randomGenerator);
bool transitionFound = false;
for (const auto &transition : transitionsDistribution)
{
auto to = transition.first;
auto limits = transition.second;
if (limits.first < random && limits.second > random)
{
state = to;
stateSequence.push_back(state);
transitionFound = true;
break;
}
}
if (transitionFound)
{
if (auto trafficState =
std::get_if<DRAMSys::Config::TraceGeneratorTrafficState>(&conf.states.at(state)))
totalTransactions += trafficState->numRequests;
if (totalTransactions < maxTransactions)
continue;
}
break;
}
stateIt = stateSequence.cbegin();
}
bool TrafficGenerator::hasStateTransitionEvent(const std::string &eventName) const
{
auto it = stateTranstitionEvents.find(eventName);
if (it == stateTranstitionEvents.end())
return false;
return true;
}
const sc_core::sc_event &TrafficGenerator::getStateTransitionEvent(const std::string &eventName) const
{
auto it = stateTranstitionEvents.find(eventName);
if (it == stateTranstitionEvents.end())
SC_REPORT_FATAL("TraceSetup", "StateTransitionEvent not found.");
return it->second.event;
}
uint64_t TrafficGenerator::getTotalTransactions() const
{
uint64_t totalTransactions = 0;
for (auto state : stateSequence)
{
if (auto trafficState = std::get_if<DRAMSys::Config::TraceGeneratorTrafficState>(&conf.states.at(state)))
totalTransactions += trafficState->numRequests;
}
if (totalTransactions > maxTransactions)
totalTransactions = maxTransactions;
return totalTransactions;
}
void TrafficGenerator::waitUntil(const sc_core::sc_event *ev)
{
startEvent = ev;
}
void TrafficGenerator::transitionToNextState()
{
++stateIt;
if (stateIt == stateSequence.cend() || transactionsSent >= maxTransactions)
{
// No transition performed.
finished = true;
return;
}
currentState = *stateIt;
// Notify
for (auto &it : stateTranstitionEvents)
{
if (it.second.stateId == currentState)
it.second.event.notify();
}
if (auto idleState = std::get_if<DRAMSys::Config::TraceGeneratorIdleState>(&conf.states.at(currentState)))
{
currentClksToIdle += idleState->idleClks;
transitionToNextState();
return;
}
else if (auto trafficState =
std::get_if<DRAMSys::Config::TraceGeneratorTrafficState>(&conf.states.at(currentState)))
{
uint64_t minAddress = evaluateMinAddress(*trafficState);
uint64_t maxAddress = evaluateMaxAddress(*trafficState, simMemSizeInBytes);
randomAddressDistribution = std::uniform_int_distribution<uint64_t>(minAddress, maxAddress);
currentClksPerRequest = trafficState->clksPerRequest.value_or(defaultClksPerRequest);
}
currentAddress = 0x00;
transactionsSentInCurrentState = 0;
}
void TrafficGenerator::prepareNextPayload()
{
if (transactionsSent >= maxTransactions)
{
finished = true;
return;
}
if (startEvent && transactionsSent == 0)
wait(*startEvent);
if (auto trafficState =
std::get_if<DRAMSys::Config::TraceGeneratorTrafficState>(&conf.states.at(currentState)))
{
if (transactionsSentInCurrentState >= trafficState->numRequests)
transitionToNextState();
}
// In case we are in an idle state right at the beginning of the simulation,
// set the clksToIdle and transition to the next state.
if (auto idleState =
std::get_if<DRAMSys::Config::TraceGeneratorIdleState>(&conf.states.at(currentState)))
{
currentClksToIdle = idleState->idleClks;
transitionToNextState();
}
}
void TrafficGenerator::payloadSent()
{
// Reset clks to idle.
currentClksToIdle = 0;
transactionsSentInCurrentState++;
}
tlm::tlm_command TrafficGenerator::getNextCommand()
{
// An idle state should never reach this method.
auto &state = std::get<DRAMSys::Config::TraceGeneratorTrafficState>(conf.states.at(currentState));
tlm_command command;
if (randomDistribution(randomGenerator) < state.rwRatio)
command = tlm::TLM_READ_COMMAND;
else
command = tlm::TLM_WRITE_COMMAND;
return command;
}
sc_core::sc_time TrafficGenerator::getGeneratorClk() const
{
return generatorClk;
}
uint64_t TrafficGenerator::getNextAddress()
{
using DRAMSys::Config::AddressDistribution;
// An idle state should never reach this method.
auto &state = std::get<DRAMSys::Config::TraceGeneratorTrafficState>(conf.states.at(currentState));
uint64_t minAddress = evaluateMinAddress(state);
uint64_t maxAddress = evaluateMaxAddress(state, simMemSizeInBytes);
if (state.addressDistribution == AddressDistribution::Sequential)
{
uint64_t addressIncrement = state.addressIncrement.value_or(defaultAddressIncrement);
uint64_t address = currentAddress;
currentAddress += addressIncrement;
if (currentAddress > maxAddress)
currentAddress = minAddress;
return address;
}
else if (state.addressDistribution == AddressDistribution::Random)
{
return randomAddressDistribution(randomGenerator);
}
else
{
return 0x00;
}
}
uint64_t TrafficGenerator::evaluateMinAddress(const DRAMSys::Config::TraceGeneratorTrafficState &state)
{
return state.minAddress.value_or(0x00);
}
uint64_t TrafficGenerator::evaluateMaxAddress(const DRAMSys::Config::TraceGeneratorTrafficState &state,
uint64_t simMemSizeInBytes)
{
return state.maxAddress.value_or(simMemSizeInBytes - 1);
}
TrafficGeneratorHammer::TrafficGeneratorHammer(const sc_core::sc_module_name &name, const Configuration& config,
const DRAMSys::Config::TraceHammer &conf, TraceSetup& setup)
: TrafficGeneratorIf(name, config, setup, 1, 1, config.memSpec->defaultBytesPerBurst),
generatorClk(evaluateGeneratorClk(conf)), rowIncrement(conf.rowIncrement), numRequests(conf.numRequests)
{
}
tlm::tlm_command TrafficGeneratorHammer::getNextCommand()
{
return tlm::TLM_READ_COMMAND;
}
sc_core::sc_time TrafficGeneratorHammer::getGeneratorClk() const
{
return generatorClk;
}
uint64_t TrafficGeneratorHammer::getNextAddress()
{
if (currentAddress == 0x0)
currentAddress = rowIncrement;
else
currentAddress = 0x0;
return currentAddress;
}
void TrafficGeneratorHammer::prepareNextPayload()
{
if (transactionsSent >= numRequests)
finished = true;
}

View File

@@ -0,0 +1,150 @@
/*
* Copyright (c) 2015, Technische Universität 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
* Derek Christ
*/
#ifndef TRAFFICGENERATOR_H
#define TRAFFICGENERATOR_H
#include "TrafficInitiator.h"
#include "TraceSetup.h"
#include <cstdint>
#include <map>
#include <random>
class TrafficGeneratorIf : public TrafficInitiator
{
public:
TrafficGeneratorIf(const sc_core::sc_module_name &name, const Configuration& config, TraceSetup& setup,
unsigned int maxPendingReadRequests, unsigned int maxPendingWriteRequests,
unsigned int dataLength);
private:
void sendNextPayload() override;
virtual void prepareNextPayload(){};
virtual uint64_t getNextAddress() = 0;
virtual tlm::tlm_command getNextCommand() = 0;
virtual sc_core::sc_time getGeneratorClk() const = 0;
virtual void payloadSent(){};
virtual uint64_t clksPerRequest() const { return 1; }
virtual uint64_t clksToIdle() const { return 0; }
};
class TrafficGenerator : public TrafficGeneratorIf
{
public:
TrafficGenerator(const sc_core::sc_module_name &name, const Configuration& config,
const DRAMSys::Config::TraceGenerator &conf, TraceSetup& setup);
uint64_t getTotalTransactions() const;
void waitUntil(const sc_core::sc_event *ev);
bool hasStateTransitionEvent(const std::string &eventName) const;
const sc_core::sc_event &getStateTransitionEvent(const std::string &eventName) const;
private:
static uint64_t evaluateMinAddress(const DRAMSys::Config::TraceGeneratorTrafficState& state);
static uint64_t evaluateMaxAddress(const DRAMSys::Config::TraceGeneratorTrafficState& state,
uint64_t simMemSizeInBytes);
void prepareNextPayload() override;
uint64_t getNextAddress() override;
tlm::tlm_command getNextCommand() override;
sc_core::sc_time getGeneratorClk() const override;
void payloadSent() override;
uint64_t clksPerRequest() const override { return currentClksPerRequest; };
uint64_t clksToIdle() const override { return currentClksToIdle; }
void calculateTransitions();
void transitionToNextState();
sc_core::sc_time generatorClk;
const DRAMSys::Config::TraceGenerator &conf;
unsigned int currentState = 0;
uint64_t currentAddress = 0x00;
uint64_t currentClksPerRequest = 1;
uint64_t transactionsSentInCurrentState = 0;
const uint64_t maxTransactions;
const uint64_t simMemSizeInBytes;
uint64_t currentClksToIdle = 0;
std::vector<unsigned int> stateSequence;
std::vector<unsigned int>::const_iterator stateIt;
struct EventPair
{
EventPair(const std::string &name, unsigned int id) : event(name.c_str()), stateId(id)
{
}
sc_core::sc_event event;
unsigned int stateId;
};
std::map<std::string, EventPair> stateTranstitionEvents;
bool idleAtStart = false;
const sc_core::sc_event *startEvent = nullptr;
std::default_random_engine randomGenerator;
std::uniform_real_distribution<float> randomDistribution = std::uniform_real_distribution<float>(0.0f, 1.0f);
std::uniform_int_distribution<uint64_t> randomAddressDistribution;
static constexpr uint64_t defaultSeed = 0;
static constexpr uint64_t defaultClksPerRequest = 1;
static constexpr uint64_t defaultAddressIncrement = 0x00;
};
class TrafficGeneratorHammer final : public TrafficGeneratorIf
{
public:
TrafficGeneratorHammer(const sc_core::sc_module_name &name, const Configuration& config,
const DRAMSys::Config::TraceHammer &conf, TraceSetup& setup);
private:
void prepareNextPayload() override;
uint64_t getNextAddress() override;
tlm::tlm_command getNextCommand() override;
sc_core::sc_time getGeneratorClk() const override;
sc_core::sc_time generatorClk;
uint64_t rowIncrement;
uint64_t currentAddress = 0x0;
uint64_t numRequests;
};
#endif // TRAFFICGENERATOR_H

View File

@@ -0,0 +1,139 @@
/*
* Copyright (c) 2015, Technische Universität 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
* Éder F. Zulian
* Felipe S. Prado
* Derek Christ
*/
#include "TrafficInitiator.h"
#include "TraceSetup.h"
using namespace sc_core;
using namespace tlm;
TrafficInitiator::TrafficInitiator(const sc_module_name &name, const Configuration& config, TraceSetup& setup,
unsigned int maxPendingReadRequests, unsigned int maxPendingWriteRequests, unsigned int defaultDataLength) :
sc_module(name),
payloadEventQueue(this, &TrafficInitiator::peqCallback),
setup(setup),
maxPendingReadRequests(maxPendingReadRequests),
maxPendingWriteRequests(maxPendingWriteRequests),
defaultDataLength(defaultDataLength),
storageEnabled(config.storeMode != Configuration::StoreMode::NoStorage),
simulationProgressBar(config.simulationProgressBar)
{
SC_THREAD(sendNextPayload);
iSocket.register_nb_transport_bw(this, &TrafficInitiator::nb_transport_bw);
}
void TrafficInitiator::terminate()
{
std::cout << sc_time_stamp() << " " << this->name() << " terminated " << std::endl;
setup.trafficInitiatorTerminates();
}
tlm_sync_enum TrafficInitiator::nb_transport_bw(tlm_generic_payload &payload,
tlm_phase &phase, sc_time &bwDelay)
{
payloadEventQueue.notify(payload, phase, bwDelay);
return TLM_ACCEPTED;
}
void TrafficInitiator::peqCallback(tlm_generic_payload &payload,
const tlm_phase &phase)
{
if (phase == END_REQ)
{
if (nextPayloadSendable())
sendNextPayload();
else
payloadPostponed = true;
}
else if (phase == BEGIN_RESP)
{
payload.release();
sendToTarget(payload, END_RESP, SC_ZERO_TIME);
if (simulationProgressBar)
setup.transactionFinished();
transactionsReceived++;
if (payload.get_command() == tlm::TLM_READ_COMMAND)
pendingReadRequests--;
else if (payload.get_command() == tlm::TLM_WRITE_COMMAND)
pendingWriteRequests--;
// If the initiator wasn't able to send the next payload in the END_REQ phase, do it now.
if (payloadPostponed && nextPayloadSendable())
{
sendNextPayload();
payloadPostponed = false;
}
// If all answers were received:
if (finished && transactionsSent == transactionsReceived)
terminate();
}
else
{
SC_REPORT_FATAL("TrafficInitiator", "PEQ was triggered with unknown phase");
}
}
void TrafficInitiator::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);
}
bool TrafficInitiator::nextPayloadSendable() const
{
// If either the maxPendingReadRequests or maxPendingWriteRequests
// limit is reached, do not send next payload.
if (((pendingReadRequests >= maxPendingReadRequests) && (maxPendingReadRequests != 0))
|| ((pendingWriteRequests >= maxPendingWriteRequests) && (maxPendingWriteRequests != 0)))
return false;
else
return true;
}
sc_core::sc_time TrafficInitiator::evaluateGeneratorClk(const DRAMSys::Config::TrafficInitiator &conf)
{
double frequencyMHz = conf.clkMhz;
sc_time playerClk = sc_time(1.0 / frequencyMHz, SC_US);
return playerClk;
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright (c) 2015, Technische Universität 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
* Éder F. Zulian
* Felipe S. Prado
* Derek Christ
*/
#ifndef TRAFFICINITIATOR_H
#define TRAFFICINITIATOR_H
#include <deque>
#include <iostream>
#include <string>
#include <tlm>
#include <systemc>
#include <tlm_utils/simple_initiator_socket.h>
#include <tlm_utils/peq_with_cb_and_phase.h>
#include <DRAMSys/configuration/Configuration.h>
#include <DRAMSys/common/DebugManager.h>
#include "TraceSetup.h"
class TrafficInitiator : public sc_core::sc_module
{
public:
tlm_utils::simple_initiator_socket<TrafficInitiator> iSocket;
TrafficInitiator(const sc_core::sc_module_name &name, const Configuration& config, TraceSetup& setup,
unsigned int maxPendingReadRequests, unsigned int maxPendingWriteRequests, unsigned int defaultDataLength);
SC_HAS_PROCESS(TrafficInitiator);
virtual void sendNextPayload() = 0;
protected:
static sc_core::sc_time evaluateGeneratorClk(const DRAMSys::Config::TrafficInitiator &conf);
tlm_utils::peq_with_cb_and_phase<TrafficInitiator> payloadEventQueue;
void terminate();
TraceSetup& setup;
void sendToTarget(tlm::tlm_generic_payload &payload, const tlm::tlm_phase &phase,
const sc_core::sc_time &delay);
uint64_t transactionsReceived = 0;
uint64_t transactionsSent = 0;
unsigned int pendingReadRequests = 0;
unsigned int pendingWriteRequests = 0;
const unsigned int maxPendingReadRequests = 0;
const unsigned int maxPendingWriteRequests = 0;
bool payloadPostponed = false;
bool finished = false;
const unsigned int defaultDataLength;
const bool storageEnabled;
const bool simulationProgressBar;
// 0 disables the max value.
static constexpr unsigned int defaultMaxPendingWriteRequests = 0;
static constexpr unsigned int defaultMaxPendingReadRequests = 0;
private:
tlm::tlm_sync_enum nb_transport_bw(tlm::tlm_generic_payload &payload, tlm::tlm_phase &phase,
sc_core::sc_time &bwDelay);
void peqCallback(tlm::tlm_generic_payload &payload, const tlm::tlm_phase &phase);
bool nextPayloadSendable() const;
};
#endif // TRAFFICINITIATOR_H