Set up testing infrastructure for Cache

This commit is contained in:
2023-01-27 12:08:51 +01:00
parent 45e31f5b5a
commit a4fe32703c
14 changed files with 1221 additions and 17 deletions

View File

@@ -43,14 +43,25 @@ 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})
list(FILTER SOURCE_FILES EXCLUDE REGEX "main.cpp")
add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES} ${HEADER_FILES})
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(${PROJECT_NAME}
PUBLIC
Threads::Threads
DRAMSys::libdramsys
)
add_executable(DRAMSys
main.cpp
)
target_link_libraries(DRAMSys
PRIVATE
Threads::Threads
SystemC::systemc
DRAMSys::libdramsys
DRAMSys_Simulator
)
build_source_group()

View File

@@ -33,13 +33,13 @@
* Derek Christ
*/
#include "Initiator.h"
#include "MemoryManager.h"
#include "SimpleInitiator.h"
#include "generator/TrafficGenerator.h"
#include "hammer/RowHammer.h"
#include "player/StlPlayer.h"
#include "util.h"
#include "simulator/Initiator.h"
#include "simulator/MemoryManager.h"
#include "simulator/SimpleInitiator.h"
#include "simulator/generator/TrafficGenerator.h"
#include "simulator/hammer/RowHammer.h"
#include "simulator/player/StlPlayer.h"
#include "simulator/util.h"
#include <DRAMSys/simulation/DRAMSysRecordable.h>

View File

@@ -23,7 +23,8 @@ Cache::Cache(const sc_module_name &name,
std::size_t maxTargetListSize,
bool storageEnabled,
sc_core::sc_time cycleTime,
std::size_t hitCycles) :
std::size_t hitCycles,
MemoryManager &memoryManager) :
sc_module(name),
payloadEventQueue(this, &Cache::peqCallback),
storageEnabled(storageEnabled),
@@ -39,7 +40,7 @@ Cache::Cache(const sc_module_name &name,
mshrDepth(mshrDepth),
writeBufferDepth(writeBufferDepth),
maxTargetListSize(maxTargetListSize),
memoryManager(storageEnabled)
memoryManager(memoryManager)
{
iSocket.register_nb_transport_bw(this, &Cache::nb_transport_bw);
tSocket.register_nb_transport_fw(this, &Cache::nb_transport_fw);
@@ -601,7 +602,7 @@ void Cache::processMshrResponse()
else
{
hitIt->hitDelayStarted = true;
payloadEventQueue.notify(returnTrans, MISS_HANDLING, hitLatency + sc_time(1, SC_NS));
payloadEventQueue.notify(returnTrans, MISS_HANDLING, hitLatency);
return;
}

View File

@@ -61,7 +61,8 @@ public:
std::size_t maxTargetListSize,
bool storageEnabled,
sc_core::sc_time cycleTime,
std::size_t hitCycles);
std::size_t hitCycles,
MemoryManager &memoryManager);
SC_HAS_PROCESS(Cache);
private:
@@ -196,5 +197,5 @@ private:
sc_core::sc_time ceilTime(const sc_core::sc_time &inTime) const;
sc_core::sc_time ceilDelay(const sc_core::sc_time &inDelay) const;
MemoryManager memoryManager;
MemoryManager &memoryManager;
};

View File

@@ -0,0 +1,313 @@
/*
* 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:
* Christian Malek
* Derek Christ
*/
#include "EccModule.h"
#include "DRAMSys/common/dramExtensions.h"
#include <fstream>
using namespace sc_core;
using namespace tlm;
EccModule::EccModule(sc_module_name name, AddressDecoder const &addressDecoder) :
sc_core::sc_module(name),
payloadEventQueue(this, &EccModule::peqCallback),
addressDecoder(addressDecoder),
memoryManager(false)
{
iSocket.register_nb_transport_bw(this, &EccModule::nb_transport_bw);
tSocket.register_nb_transport_fw(this, &EccModule::nb_transport_fw);
}
tlm::tlm_sync_enum EccModule::nb_transport_fw(tlm::tlm_generic_payload &payload,
tlm::tlm_phase &phase,
sc_core::sc_time &fwDelay)
{
if (phase == BEGIN_REQ)
{
payload.acquire();
}
payloadEventQueue.notify(payload, phase, fwDelay);
return TLM_ACCEPTED;
}
tlm::tlm_sync_enum EccModule::nb_transport_bw(tlm::tlm_generic_payload &payload,
tlm::tlm_phase &phase,
sc_core::sc_time &bwDelay)
{
payloadEventQueue.notify(payload, phase, bwDelay);
return TLM_ACCEPTED;
}
void EccModule::peqCallback(tlm::tlm_generic_payload &cbPayload, const tlm::tlm_phase &cbPhase)
{
if (cbPhase == BEGIN_REQ) // from initiator
{
// Put transaction into latency map
payloadMap.emplace(&cbPayload, sc_time_stamp());
if (!targetBusy)
{
targetBusy = true;
tlm_phase tPhase = BEGIN_REQ;
sc_time tDelay = SC_ZERO_TIME;
DecodedAddress decodedAddress = addressDecoder.decodeAddress(cbPayload.get_address());
decodedAddress = calculateOffsetAddress(decodedAddress);
// Update the original address to account for the offsets
cbPayload.set_address(addressDecoder.encodeAddress(decodedAddress));
auto currentBlock = alignToBlock(decodedAddress.column);
// In case there is no entry yet.
activeEccBlocks.try_emplace(decodedAddress.bank);
#ifdef ECC_ENABLE
if (!activeEccBlock(decodedAddress.bank, decodedAddress.row, currentBlock))
{
blockedRequest = &cbPayload;
auto &eccFifo = activeEccBlocks[decodedAddress.bank];
eccFifo.push_back({currentBlock, decodedAddress.row});
// Only hold 4 elements at max.
if (eccFifo.size() >= 4)
eccFifo.pop_front();
tlm::tlm_generic_payload *eccPayload = generateEccPayload(decodedAddress);
iSocket->nb_transport_fw(*eccPayload, tPhase, tDelay);
}
else
#endif
{
iSocket->nb_transport_fw(cbPayload, tPhase, tDelay);
}
}
else
{
pendingRequest = &cbPayload;
}
}
else if (cbPhase == END_REQ) // from target
{
// Send payload to inititator in case it is not an ECC transaction
if (cbPayload.get_extension<EccExtension>() == nullptr)
{
tlm_phase tPhase = END_REQ;
sc_time tDelay = SC_ZERO_TIME;
tSocket->nb_transport_bw(cbPayload, tPhase, tDelay);
}
if (blockedRequest != nullptr)
{
tlm_generic_payload &tPayload = *blockedRequest;
blockedRequest = nullptr;
tlm_phase tPhase = BEGIN_REQ;
sc_time tDelay = SC_ZERO_TIME;
iSocket->nb_transport_fw(tPayload, tPhase, tDelay);
// Do not attempt to send another pending request and hold targetBusy high
return;
}
if (pendingRequest != nullptr)
{
tlm_generic_payload &tPayload = *pendingRequest;
tlm_phase tPhase = BEGIN_REQ;
sc_time tDelay = SC_ZERO_TIME;
DecodedAddress decodedAddress = addressDecoder.decodeAddress(tPayload.get_address());
decodedAddress = calculateOffsetAddress(decodedAddress);
auto currentBlock = alignToBlock(decodedAddress.column);
#ifdef ECC_ENABLE
if (!activeEccBlock(decodedAddress.bank, decodedAddress.row, currentBlock))
{
blockedRequest = pendingRequest;
pendingRequest = nullptr;
auto &eccFifo = activeEccBlocks[decodedAddress.bank];
eccFifo.push_back({currentBlock, decodedAddress.row});
// Only hold 4 elements at max.
if (eccFifo.size() >= 4)
eccFifo.pop_front();
tlm::tlm_generic_payload *eccPayload = generateEccPayload(decodedAddress);
iSocket->nb_transport_fw(*eccPayload, tPhase, tDelay);
}
else
#endif
{
iSocket->nb_transport_fw(tPayload, tPhase, tDelay);
pendingRequest = nullptr;
}
}
else
{
assert(!pendingRequest);
assert(!blockedRequest);
targetBusy = false;
}
}
else if (cbPhase == BEGIN_RESP) // from memory controller
{
// Send payload to inititator in case it is not an ECC transaction
if (cbPayload.get_extension<EccExtension>() == nullptr)
{
tlm_phase tPhase = BEGIN_RESP;
sc_time tDelay = SC_ZERO_TIME;
tlm_sync_enum returnValue = tSocket->nb_transport_bw(cbPayload, tPhase, tDelay);
// Early completion from initiator
if (returnValue == TLM_UPDATED)
{
payloadEventQueue.notify(cbPayload, tPhase, tDelay);
}
Latency latency = sc_time_stamp() - payloadMap.at(&cbPayload);
payloadMap.erase(&cbPayload);
latency = roundLatency(latency);
latencyMap.try_emplace(latency, 0);
latencyMap.at(latency)++;
}
else
{
// Send END_RESP by ourselfes
tlm_phase tPhase = END_RESP;
sc_time tDelay = SC_ZERO_TIME;
iSocket->nb_transport_fw(cbPayload, tPhase, tDelay);
}
}
else if (cbPhase == END_RESP) // from initiator
{
{
tlm_phase tPhase = END_RESP;
sc_time tDelay = SC_ZERO_TIME;
iSocket->nb_transport_fw(cbPayload, tPhase, tDelay);
}
cbPayload.release();
}
else
{
SC_REPORT_FATAL(0, "Payload event queue in arbiter was triggered with unknown phase");
}
}
tlm::tlm_generic_payload *EccModule::generateEccPayload(DecodedAddress decodedAddress)
{
unsigned int eccAtom = decodedAddress.column / 512;
uint64_t eccColumn = 1792 + eccAtom * 32;
decodedAddress.column = eccColumn;
uint64_t eccAddress = addressDecoder.encodeAddress(decodedAddress);
tlm_generic_payload &payload = memoryManager.allocate(32);
payload.acquire();
payload.set_address(eccAddress);
payload.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
payload.set_dmi_allowed(false);
payload.set_byte_enable_length(0);
payload.set_data_length(32);
payload.set_streaming_width(32);
payload.set_command(tlm::TLM_READ_COMMAND);
payload.set_extension<EccExtension>(new EccExtension);
return &payload;
}
unsigned int EccModule::alignToBlock(unsigned column)
{
return column & ~(512 - 1);
}
DecodedAddress EccModule::calculateOffsetAddress(DecodedAddress decodedAddress)
{
unsigned int newRow =
std::floor((decodedAddress.row * 256 + decodedAddress.column) / 1792) + decodedAddress.row;
unsigned int newColumn = (decodedAddress.row * 256 + decodedAddress.column) % 1792;
DecodedAddress offsetAddress(decodedAddress);
offsetAddress.row = newRow;
offsetAddress.column = newColumn;
return offsetAddress;
}
void EccModule::end_of_simulation()
{
uint64_t latencies = 0;
uint64_t numberOfLatencies = 0;
for (auto const &[latency, occurences] : latencyMap)
{
latencies += (latency.to_double() / 1000.0) * occurences;
numberOfLatencies += occurences;
}
std::cout << "Average latency: " << static_cast<double>(latencies) / numberOfLatencies << std::endl;
}
sc_time EccModule::roundLatency(sc_time latency)
{
static const sc_time BUCKET_SIZE = sc_time(1, SC_NS);
latency += BUCKET_SIZE / 2;
latency = latency - (latency % BUCKET_SIZE);
return latency;
}
bool EccModule::activeEccBlock(Bank bank, Row row, Block block) const
{
auto eccIt = std::find_if(activeEccBlocks.at(bank).cbegin(), activeEccBlocks.at(bank).cend(),
[block, row](EccIdentifier identifier) {
return (identifier.first == block) && (identifier.second == row);
});
return eccIt != activeEccBlocks.at(bank).cend();
}

View File

@@ -0,0 +1,107 @@
/*
* 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:
* Christian Malek
* Derek Christ
*/
#ifndef ECCMODULE_H
#define ECCMODULE_H
#include "simulator/MemoryManager.h"
#include <DRAMSys/simulation/AddressDecoder.h>
#include <systemc>
#include <tlm_utils/peq_with_cb_and_phase.h>
#include <tlm_utils/simple_initiator_socket.h>
#include <tlm_utils/simple_target_socket.h>
#include <unordered_map>
#include <map>
#include <deque>
class EccModule : public sc_core::sc_module
{
public:
tlm_utils::simple_initiator_socket<EccModule> iSocket;
tlm_utils::simple_target_socket<EccModule> tSocket;
EccModule(sc_core::sc_module_name name, AddressDecoder const &addressDecoder);
SC_HAS_PROCESS(EccModule);
private:
using Block = uint64_t;
using Row = uint64_t;
using Bank = unsigned int;
using EccIdentifier = std::pair<Block, Row>;
using EccQueue = std::deque<EccIdentifier>;
static DecodedAddress calculateOffsetAddress(DecodedAddress decodedAddress);
static sc_core::sc_time roundLatency(sc_core::sc_time latency);
bool activeEccBlock(Bank bank, Row row, Block block) const;
void end_of_simulation() override;
void peqCallback(tlm::tlm_generic_payload &payload, const tlm::tlm_phase &phase);
tlm::tlm_sync_enum nb_transport_fw(tlm::tlm_generic_payload &payload,
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);
tlm::tlm_generic_payload *generateEccPayload(DecodedAddress decodedAddress);
static unsigned int alignToBlock(unsigned int column);
tlm_utils::peq_with_cb_and_phase<EccModule> payloadEventQueue;
tlm::tlm_generic_payload *pendingRequest = nullptr;
tlm::tlm_generic_payload *blockedRequest = nullptr;
bool targetBusy = false;
const sc_core::sc_time tCK;
MemoryManager memoryManager;
AddressDecoder const &addressDecoder;
std::unordered_map<Bank, EccQueue> activeEccBlocks;
using EccPayload = tlm::tlm_generic_payload *;
using StartTime = sc_core::sc_time;
std::unordered_map<tlm::tlm_generic_payload*, StartTime> payloadMap;
using Latency = sc_core::sc_time;
std::map<Latency, uint64_t> latencyMap;
};
#endif // ECCMODULE_H

View File

@@ -4,3 +4,4 @@ add_subdirectory(tests_configuration)
add_subdirectory(tests_dramsys)
add_subdirectory(tests_regression)
add_subdirectory(tests_util)
add_subdirectory(tests_simulator)

View File

@@ -0,0 +1,27 @@
###############################################
### tests_simulator ###
###############################################
cmake_minimum_required(VERSION 3.1.0)
project(tests_simulator)
add_executable(${PROJECT_NAME}
main.cpp
cache/tests_cache.cpp
cache/TargetMemory.cpp
cache/ListInitiator.cpp
)
set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER tests/simulator)
target_link_libraries(${PROJECT_NAME} PRIVATE
DRAMSys_Simulator
gtest_main
)
gtest_discover_tests(${PROJECT_NAME}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
build_source_group()

View File

@@ -0,0 +1,189 @@
/*
* Copyright (c) 2023, 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:
* Derek Christ
*/
#include "ListInitiator.h"
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <systemc>
#include <tlm>
#include <utility>
ListInitiator::ListInitiator(const sc_core::sc_module_name &name, MemoryManager &memoryManager)
: sc_core::sc_module(name),
iSocket("iSocket"),
peq(this, &ListInitiator::peqCallback),
memoryManager(memoryManager)
{
iSocket.register_nb_transport_bw(this, &ListInitiator::nb_transport_bw);
SC_THREAD(process);
}
void ListInitiator::process()
{
for (auto &testTransactionData : testTransactionList)
{
wait(testTransactionData.startTime - sc_core::sc_time_stamp());
tlm::tlm_command command =
testTransactionData.command == TestTransactionData::Command::Write
? tlm::TLM_WRITE_COMMAND
: tlm::TLM_READ_COMMAND;
auto &trans = memoryManager.allocate(testTransactionData.dataLength);
trans.acquire();
TestExtension *ext = new TestExtension(testTransactionData);
trans.set_auto_extension(ext);
trans.set_command(command);
trans.set_address(testTransactionData.address);
trans.set_data_length(testTransactionData.dataLength);
trans.set_streaming_width(testTransactionData.dataLength);
trans.set_byte_enable_ptr(nullptr);
trans.set_dmi_allowed(false);
trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
if (trans.is_write())
std::memcpy(trans.get_data_ptr(), &testTransactionData.data, testTransactionData.dataLength);
if (requestInProgress != nullptr)
{
wait(endRequest);
}
requestInProgress = &trans;
tlm::tlm_phase phase = tlm::BEGIN_REQ;
sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
std::cout << "\033[1;31m(" << name() << ")@" << std::setfill(' ') << std::setw(12)
<< sc_core::sc_time_stamp() << ": " << std::setw(12)
<< (command == tlm::TLM_WRITE_COMMAND ? "Write to " : "Read from ")
<< "Addr = " << std::setfill('0') << std::setw(8) << std::dec
<< testTransactionData.address << " Data = "
<< "0x" << std::setfill('0') << std::setw(8) << std::hex
<< testTransactionData.data << "(nb_transport) \033[0m" << std::endl;
tlm::tlm_sync_enum status = iSocket->nb_transport_fw(trans, phase, delay);
if (status == tlm::TLM_UPDATED)
{
peq.notify(trans, phase, delay);
}
else if (status == tlm::TLM_COMPLETED)
{
requestInProgress = nullptr;
checkTransaction(trans);
trans.release();
}
}
}
tlm::tlm_sync_enum ListInitiator::nb_transport_bw(tlm::tlm_generic_payload &trans,
tlm::tlm_phase &phase,
sc_core::sc_time &delay)
{
peq.notify(trans, phase, delay);
return tlm::TLM_ACCEPTED;
}
void ListInitiator::peqCallback(tlm::tlm_generic_payload &trans, const tlm::tlm_phase &phase)
{
if (phase == tlm::END_REQ || (&trans == requestInProgress && phase == tlm::BEGIN_RESP))
{
requestInProgress = nullptr;
endRequest.notify();
}
else if (phase == tlm::BEGIN_REQ || phase == tlm::END_RESP)
{
SC_REPORT_FATAL(name(), "Illegal transaction phase received");
}
if (phase == tlm::BEGIN_RESP)
{
checkTransaction(trans);
tlm::tlm_phase fw_phase = tlm::END_RESP;
sc_core::sc_time delay = sc_core::sc_time(1, sc_core::SC_NS);
iSocket->nb_transport_fw(trans, fw_phase, delay);
trans.release();
}
}
void ListInitiator::checkTransaction(tlm::tlm_generic_payload &trans)
{
if (trans.is_response_error())
{
SC_REPORT_ERROR(name(), "Transaction returned with error!");
}
tlm::tlm_command command = trans.get_command();
uint64_t transData{};
if (trans.get_data_length() == 1)
transData = *reinterpret_cast<uint8_t *>(trans.get_data_ptr());
else if (trans.get_data_length() == 2)
transData = *reinterpret_cast<uint16_t *>(trans.get_data_ptr());
else if (trans.get_data_length() == 4)
transData = *reinterpret_cast<uint32_t *>(trans.get_data_ptr());
else if (trans.get_data_length() == 8)
transData = *reinterpret_cast<uint64_t *>(trans.get_data_ptr());
TestExtension *ext = nullptr;
trans.get_extension(ext);
TestTransactionData data = ext->getTestData();
std::cout << "\033[1;31m(" << name() << ")@" << std::setfill(' ') << std::setw(12)
<< sc_core::sc_time_stamp() << ": " << std::setw(12)
<< (command == tlm::TLM_WRITE_COMMAND ? "Check Write " : "Check Read ")
<< "Addr = " << std::setfill('0') << std::setw(8) << std::dec << data.address
<< " Data = "
<< "0x" << std::setfill('0') << std::setw(8) << std::hex << transData << "\033[0m"
<< std::endl;
if (data.expectedEndTime != sc_core::sc_time_stamp())
{
SC_REPORT_FATAL(name(), "NOT EXPECTED TIME");
}
if (trans.is_read() && data.data != transData)
{
SC_REPORT_FATAL(name(), "NOT EXPECTED DATA");
}
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright (c) 2023, 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:
* Derek Christ
*/
#include "simulator/MemoryManager.h"
#include <tlm_utils/peq_with_cb_and_phase.h>
#include <tlm_utils/simple_initiator_socket.h>
class ListInitiator : public sc_core::sc_module
{
public:
tlm_utils::simple_initiator_socket<ListInitiator> iSocket;
SC_HAS_PROCESS(ListInitiator);
ListInitiator(const sc_core::sc_module_name &name, MemoryManager &memoryManager);
struct TestTransactionData
{
sc_core::sc_time startTime;
sc_core::sc_time expectedEndTime;
enum class Command
{
Read,
Write,
} command;
uint64_t address;
uint32_t dataLength;
uint64_t data;
};
void appendTestTransactionList(const std::vector<TestTransactionData> &testTransactionList)
{
std::copy(testTransactionList.cbegin(), testTransactionList.cend(), std::back_inserter(this->testTransactionList));
}
private:
class TestExtension : public tlm::tlm_extension<TestExtension>
{
public:
TestExtension(TestTransactionData data) : data(std::move(data)) {}
tlm_extension_base *clone() const { return new TestExtension(data); }
void copy_from(const tlm_extension_base &ext)
{
const TestExtension &cpyFrom = static_cast<const TestExtension &>(ext);
data = cpyFrom.getTestData();
}
TestTransactionData getTestData() const { return data; }
private:
TestTransactionData data;
};
void process();
tlm::tlm_sync_enum nb_transport_bw(tlm::tlm_generic_payload &trans,
tlm::tlm_phase &phase,
sc_core::sc_time &delay);
void peqCallback(tlm::tlm_generic_payload &trans, const tlm::tlm_phase &phase);
void checkTransaction(tlm::tlm_generic_payload &trans);
std::vector<TestTransactionData> testTransactionList;
sc_core::sc_event endRequest;
tlm_utils::peq_with_cb_and_phase<ListInitiator> peq;
tlm::tlm_generic_payload *requestInProgress = nullptr;
MemoryManager &memoryManager;
};

View File

@@ -0,0 +1,231 @@
/*
* Copyright (c) 2023, 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:
* Derek Christ
*/
#include "TargetMemory.h"
#include <algorithm>
#include <cstddef>
#include <iomanip>
#include <iostream>
DECLARE_EXTENDED_PHASE(INTERNAL);
TargetMemory::TargetMemory(const sc_core::sc_module_name &name,
sc_core::sc_time acceptDelay,
sc_core::sc_time memoryLatency,
std::size_t bufferSize)
: sc_core::sc_module(name),
tSocket("tSocket"),
bufferSize(bufferSize),
peq(this, &TargetMemory::peqCallback),
acceptDelay(acceptDelay),
memoryLatency(memoryLatency)
{
tSocket.register_nb_transport_fw(this, &TargetMemory::nb_transport_fw);
memory.reserve(SIZE);
std::fill(memory.begin(), memory.end(), 0);
}
tlm::tlm_sync_enum TargetMemory::nb_transport_fw(tlm::tlm_generic_payload &trans,
tlm::tlm_phase &phase,
sc_core::sc_time &delay)
{
peq.notify(trans, phase, delay);
return tlm::TLM_ACCEPTED;
}
void TargetMemory::printBuffer(int max, int n)
{
std::cout << "\033[1;35m(" << name() << ")@" << std::setfill(' ') << std::setw(12)
<< sc_core::sc_time_stamp() << " Target Buffer: "
<< "[";
for (int i = 0; i < n; i++)
{
std::cout << "";
}
for (int i = 0; i < max - n; i++)
{
std::cout << " ";
}
std::cout << "]"
<< " (Max:" << max << ") "
<< "\033[0m" << std::endl;
std::cout.flush();
}
void TargetMemory::peqCallback(tlm::tlm_generic_payload &trans, const tlm::tlm_phase &phase)
{
sc_core::sc_time delay;
if (phase == tlm::BEGIN_REQ)
{
trans.acquire();
if (currentTransactions < bufferSize)
{
sendEndRequest(trans);
}
else
{
endRequestPending = &trans;
}
}
else if (phase == tlm::END_RESP)
{
if (!responseInProgress)
{
SC_REPORT_FATAL(name(), "Illegal transaction phase END_RESP received by target");
}
currentTransactions--;
printBuffer(bufferSize, currentTransactions);
responseInProgress = false;
if (!responseQueue.empty())
{
tlm::tlm_generic_payload *next = responseQueue.front();
responseQueue.pop();
sendResponse(*next);
}
if (endRequestPending != nullptr)
{
sendEndRequest(*endRequestPending);
endRequestPending = nullptr;
}
}
else if (phase == INTERNAL)
{
executeTransaction(trans);
if (responseInProgress)
{
responseQueue.push(&trans);
}
else
{
sendResponse(trans);
}
}
else // tlm::END_REQ or tlm::BEGIN_RESP
{
SC_REPORT_FATAL(name(), "Illegal transaction phase received");
}
}
void TargetMemory::sendEndRequest(tlm::tlm_generic_payload &trans)
{
tlm::tlm_phase bw_phase;
sc_core::sc_time delay;
// Queue the acceptance and the response with the appropriate latency
bw_phase = tlm::END_REQ;
delay = acceptDelay;
tlm::tlm_sync_enum status = tSocket->nb_transport_bw(trans, bw_phase, delay);
// Queue internal event to mark beginning of response
delay = delay + memoryLatency; // MEMORY Latency
peq.notify(trans, INTERNAL, delay);
currentTransactions++;
printBuffer(bufferSize, currentTransactions);
}
void TargetMemory::sendResponse(tlm::tlm_generic_payload &trans)
{
sc_assert(responseInProgress == false);
responseInProgress = true;
tlm::tlm_phase bw_phase = tlm::BEGIN_RESP;
sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
tlm::tlm_sync_enum status = tSocket->nb_transport_bw(trans, bw_phase, delay);
if (status == tlm::TLM_UPDATED)
{
peq.notify(trans, bw_phase, delay);
}
else if (status == tlm::TLM_COMPLETED)
{
SC_REPORT_FATAL(name(), "This transition is deprecated since TLM2.0.1");
}
trans.release();
}
void TargetMemory::executeTransaction(tlm::tlm_generic_payload &trans)
{
tlm::tlm_command command = trans.get_command();
sc_dt::uint64 address = trans.get_address();
unsigned char *data_ptr = trans.get_data_ptr();
unsigned int data_length = trans.get_data_length();
unsigned char *byte_enable_ptr = trans.get_byte_enable_ptr();
unsigned int streaming_width = trans.get_streaming_width();
if (address >= SIZE - 64)
{
trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
return;
}
if (byte_enable_ptr != nullptr)
{
trans.set_response_status(tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE);
return;
}
if (data_length > 64 || streaming_width < data_length)
{
trans.set_response_status(tlm::TLM_BURST_ERROR_RESPONSE);
return;
}
if (command == tlm::TLM_READ_COMMAND)
{
std::memcpy(trans.get_data_ptr(), &memory[trans.get_address()], trans.get_data_length());
}
else if (command == tlm::TLM_WRITE_COMMAND)
{
memcpy(&memory[trans.get_address()], trans.get_data_ptr(), trans.get_data_length());
}
std::cout << "\033[1;32m(" << name() << ")@" << std::setfill(' ') << std::setw(12)
<< sc_core::sc_time_stamp() << ": " << std::setw(12)
<< (command == tlm::TLM_WRITE_COMMAND ? "Exec. Write " : "Exec. Read ")
<< "Addr = " << std::setfill('0') << std::setw(8) << std::dec << address << " Data = "
<< "0x" << std::setfill('0') << std::setw(8) << std::hex
<< *reinterpret_cast<int *>(data_ptr) << "\033[0m" << std::endl;
trans.set_response_status(tlm::TLM_OK_RESPONSE);
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright (c) 2023, 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:
* Derek Christ
*/
#pragma once
#include <systemc>
#include <tlm>
#include <tlm_utils/peq_with_cb_and_phase.h>
#include <tlm_utils/simple_target_socket.h>
#include <queue>
class TargetMemory : public sc_core::sc_module
{
public:
tlm_utils::simple_target_socket<TargetMemory> tSocket;
SC_HAS_PROCESS(TargetMemory);
TargetMemory(const sc_core::sc_module_name &name,
sc_core::sc_time acceptDelay,
sc_core::sc_time memoryLatency,
std::size_t bufferSize = DEFAULT_BUFFER_SIZE);
private:
tlm::tlm_sync_enum nb_transport_fw(tlm::tlm_generic_payload &trans,
tlm::tlm_phase &phase,
sc_core::sc_time &delay);
void peqCallback(tlm::tlm_generic_payload &trans, const tlm::tlm_phase &phase);
void sendEndRequest(tlm::tlm_generic_payload &trans);
void sendResponse(tlm::tlm_generic_payload &trans);
void executeTransaction(tlm::tlm_generic_payload &trans);
void printBuffer(int max, int n);
static constexpr std::size_t SIZE = static_cast<const std::size_t>(64 * 1024);
static constexpr std::size_t DEFAULT_BUFFER_SIZE = 8;
const std::size_t bufferSize;
const sc_core::sc_time acceptDelay;
const sc_core::sc_time memoryLatency;
std::vector<uint8_t> memory;
unsigned int currentTransactions = 0;
bool responseInProgress = false;
tlm::tlm_generic_payload *endRequestPending = nullptr;
tlm_utils::peq_with_cb_and_phase<TargetMemory> peq;
std::queue<tlm::tlm_generic_payload *> responseQueue;
};

View File

@@ -0,0 +1,93 @@
/*
* Copyright (c) 2023, 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:
* Derek Christ
*/
#include "ListInitiator.h"
#include "TargetMemory.h"
#include <simulator/Cache.h>
#include <simulator/MemoryManager.h>
#include <gtest/gtest.h>
class SystemCTest : public testing::Test
{
public:
~SystemCTest() override { sc_core::sc_get_curr_simcontext()->reset(); }
};
class DirectMappedCache : public SystemCTest
{
protected:
DirectMappedCache()
: memoryManager(true),
initiator("ListInitiator", memoryManager),
target("TargetMemory",
sc_core::sc_time(1, sc_core::SC_NS),
sc_core::sc_time(10, sc_core::SC_NS)),
cache("Cache",
32768,
1,
32,
8,
8,
8,
true,
sc_core::sc_time(1, sc_core::SC_NS),
5,
memoryManager)
{
initiator.iSocket.bind(cache.tSocket);
cache.iSocket.bind(target.tSocket);
}
MemoryManager memoryManager;
ListInitiator initiator;
TargetMemory target;
Cache cache;
};
TEST_F(DirectMappedCache, Hello)
{
std::vector<ListInitiator::TestTransactionData> list{
{sc_core::sc_time(1000, sc_core::SC_NS),
sc_core::sc_time(1017, sc_core::SC_NS),
ListInitiator::TestTransactionData::Command::Read,
0x0,
4,
0x0}};
initiator.appendTestTransactionList(list);
sc_core::sc_start();
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2019, 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 <gtest/gtest.h>
#include <systemc>
int sc_main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}