diff --git a/src/mem/ruby/protocol/chi/tlm/SConscript b/src/mem/ruby/protocol/chi/tlm/SConscript index ad34e87f81..52729452e7 100644 --- a/src/mem/ruby/protocol/chi/tlm/SConscript +++ b/src/mem/ruby/protocol/chi/tlm/SConscript @@ -62,9 +62,12 @@ if env["CONF"]["BUILD_TLM"]: SimObject( "TlmController.py", sim_objects=["TlmController"], tags="arm isa" ) + SimObject('TlmGenerator.py', sim_objects=['TlmGenerator'], tags='arm isa') Source("utils.cc", tags="arm isa") Source("controller.cc", tags="arm isa") Source('tlm_chi.cc', tags='arm isa') + Source('tlm_chi_gen.cc', tags='arm isa') + Source('generator.cc', tags='arm isa') PySource('m5', 'tlm_chi.py') DebugFlag("TLM", tags="arm isa") diff --git a/src/mem/ruby/protocol/chi/tlm/TlmGenerator.py b/src/mem/ruby/protocol/chi/tlm/TlmGenerator.py new file mode 100644 index 0000000000..ba52d07b69 --- /dev/null +++ b/src/mem/ruby/protocol/chi/tlm/TlmGenerator.py @@ -0,0 +1,69 @@ +# -*- mode:python -*- +# Copyright (c) 2024 Arm Limited +# All rights reserved. +# +# The license below extends only to copyright in the software and shall +# not be construed as granting a license to any other intellectual +# property including but not limited to intellectual property relating +# to a hardware implementation of the functionality of the software +# licensed hereunder. You may use the software subject to the license +# terms below provided that you ensure that this notice is replicated +# unmodified and in its entirety in all distributions of the software, +# modified or unmodified, in source code or in binary form. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# 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; +# neither the name of the copyright holders 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 +# OWNER 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. + + +from m5.objects.TlmController import TlmController +from m5.params import * +from m5.SimObject import ( + PyBindMethod, + SimObject, +) + + +class TlmGenerator(SimObject): + type = "TlmGenerator" + cxx_header = "mem/ruby/protocol/chi/tlm/generator.hh" + cxx_class = "gem5::tlm::chi::TlmGenerator" + + cxx_exports = [ + PyBindMethod("scheduleTransaction"), + ] + + _transactions = [] + + def injectAt(self, when, payload, phase): + from m5.tlm_chi import Transaction + + transaction = Transaction(payload, phase) + self._transactions.append((when, transaction)) + return transaction + + def init(self): + for when, tr in self._transactions: + self.getCCObject().scheduleTransaction(when, tr) + + cpu_id = Param.Int("TlmGenerator CPU identifier") + chi_controller = Param.TlmController("TLM-to-Ruby CacheController") diff --git a/src/mem/ruby/protocol/chi/tlm/generator.cc b/src/mem/ruby/protocol/chi/tlm/generator.cc new file mode 100644 index 0000000000..776454dcad --- /dev/null +++ b/src/mem/ruby/protocol/chi/tlm/generator.cc @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2024 Arm Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders 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 + * OWNER 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. + */ + +#include "mem/ruby/protocol/chi/tlm/generator.hh" + +#include "mem/ruby/protocol/chi/tlm/controller.hh" +#include "debug/TLM.hh" + +namespace gem5 { + +namespace tlm::chi { + +bool +TlmGenerator::Transaction::Expectation::run(Transaction *tran) +{ + auto res_print = csprintf("Checking %s...", name()); + if (cb(tran)) { + inform("%s\n", res_print + " Success "); + return true; + } else { + inform("%s\n", res_print + " Fail "); + return false; + } +} + +bool +TlmGenerator::Transaction::Assertion::run(Transaction *tran) +{ + if (Expectation::run(tran)) { + return true; + } else { + panic("Failing assertion\n"); + } +} + +TlmGenerator::Transaction::Transaction(ARM::CHI::Payload *pa, ARM::CHI::Phase &ph) + : passed(true), parent(nullptr), _payload(pa), _phase(ph) +{ + _payload->ref(); +} + +TlmGenerator::Transaction::~Transaction() +{ + _payload->unref(); +} + +void +TlmGenerator::Transaction::setGenerator(TlmGenerator *gen) +{ + parent = gen; +} + +std::string +TlmGenerator::Transaction::str() const +{ + return transactionToString(*_payload, _phase); +} + +void +TlmGenerator::Transaction::inject() +{ + parent->inject(this); +} + +bool +TlmGenerator::Transaction::hasCallbacks() const +{ + return !actions.empty(); +} + +bool +TlmGenerator::Transaction::failed() const +{ + return !passed; +} + +void +TlmGenerator::Transaction::addCallback(ActionPtr &&action) +{ + actions.push_back(std::move(action)); +} + +void +TlmGenerator::Transaction::runCallbacks() +{ + // print transaction + auto it = actions.begin(); + while (it != actions.end()) { + const bool is_passing = (*it)->run(this); + if (!is_passing) { + passed = false; + } + bool wait = (*it)->wait(); + + it = actions.erase(it); + + if (wait) { + break; + } + } +} + +void +TlmGenerator::TransactionEvent::process() +{ + transaction->inject(); +} + +TlmGenerator::TlmGenerator(const Params &p) + : SimObject(p), cpuId(p.cpu_id), controller(p.chi_controller) +{ + controller->bw = [this] (ARM::CHI::Payload *payload, ARM::CHI::Phase *phase) + { + this->recv(payload, phase); + }; + + registerExitCallback([this](){ passFailCheck(); }); +} + +void +TlmGenerator::scheduleTransaction(Tick when, Transaction *transaction) +{ + transaction->setGenerator(this); + + auto event = new TransactionEvent(transaction, when); + + scheduledTransactions.push(event); + + schedule(event, when); +} + +void +TlmGenerator::inject(Transaction *transaction) +{ + auto payload = transaction->payload(); + ARM::CHI::Phase &phase = transaction->phase(); + + if (transaction->hasCallbacks()) + pendingTransactions.insert({phase.txn_id, transaction}); + + DPRINTF(TLM, "[c%d] send %s\n", cpuId, transactionToString(*payload, phase)); + + controller->sendMsg(*payload, phase); +} + +void +TlmGenerator::recv(ARM::CHI::Payload *payload, ARM::CHI::Phase *phase) +{ + DPRINTF(TLM, "[c%d] rcvd %s\n", cpuId, transactionToString(*payload, *phase)); + + auto txn_id = phase->txn_id; + if (auto it = pendingTransactions.find(txn_id); + it != pendingTransactions.end()) { + // Copy the new phase + it->second->phase() = *phase; + + // Check existing expectations + it->second->runCallbacks(); + } else { + warn("Transaction untested\n"); + } +} + +void +TlmGenerator::passFailCheck() +{ + for (auto [txn_id, transaction] : pendingTransactions) { + // We are failing either if a condition hasn't been met, + // or if there are pending actions when simulation exits + if (transaction->failed()) { + inform(" Suite Fail: failed transaction "); + return; + } + if (transaction->hasCallbacks()) { + inform(" Suite Fail: non-empty action queue "); + return; + } + } + inform(" Suite Success "); +} + +} // namespace tlm::chi + +} // namespace gem5 diff --git a/src/mem/ruby/protocol/chi/tlm/generator.hh b/src/mem/ruby/protocol/chi/tlm/generator.hh new file mode 100644 index 0000000000..39f493aed0 --- /dev/null +++ b/src/mem/ruby/protocol/chi/tlm/generator.hh @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2024 Arm Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders 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 + * OWNER 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. + */ + +#ifndef __MEM_RUBY_PROTOCOL_CHI_TLM_GENERATOR_HH__ +#define __MEM_RUBY_PROTOCOL_CHI_TLM_GENERATOR_HH__ + +#include +#include + +#include + +#include "mem/ruby/protocol/chi/tlm/utils.hh" +#include "params/TlmGenerator.hh" +#include "sim/eventq.hh" +#include "sim/sim_object.hh" + +namespace gem5 { + +namespace tlm::chi { + +class CacheController; + +/** + * TlmGenerator: this class is basically a CHI-tlm traffic generator. + * Its interface is mainly allowing to inject transactions at a specific + * point in simulated time and to set expectations on what has + * to be returned to the generator. + * The intended use is as a testbench for the CHI implementation + * in ruby. As such it requires to be hooked with a TlmController + * as a bridge for converting the CHI-tlm transactions into ruby messages. + * + * +---------------+ + * +--------------+ +---------------+ | | + * | | | | | | + * | TlmGenerator |-->| TlmController |--->| Ruby | + * | |<--| |<---| | + * +--------------+ +---------------+ | | + * +---------------+ + * + * The APIs are entirely exposed to the python world for flexible + * definition of the unit tests. + * + * To inject a CHI-tlm transaction at a specific tick in the + * simulation, the following TlmGenerator method should be + * used: + * + * def injectAt(self, when, payload, phase): + * + * This will return a Transaction object and from that point that will be the + * handle for managing the transaction: either adding transaction expectations + * upon response (e.g, what will be the cacheline state), or by adding action + * callbacks (execute some logic) + */ +class TlmGenerator : public SimObject +{ + public: + PARAMS(TlmGenerator); + TlmGenerator(const Params &p); + + /** + * Transaction object + * It stores ARM::CHI::Payload and ARM::CHI::Phase objects, + * and a list of action callables which will be executed + * in the order they have been registered once a transaction + * response arrives. These could be: + * 1) Expectation callbacks (Transaction::Expectation) + * which will check a specific condition and will warn if + * the condition is not met + * 2) Assertion callbacks (Transaction::Assertion) + * Identical to expectations, they will fail simulation instead + * of warning, which means later conditions won't be checked. + * 3) Action callbacks (Transaction::Action) + * Does something without condition checking + * + * Once the response arrives, the Transaction::runCallbacks will + * enter the dispatching loop. Actions/callbacks will be dispatched + * until the list is empty or until a waiting action is encountered. + * This will break the dispatching loop. + */ + class Transaction + { + public: + /** + * Action: + * Does something without condition checking. It is + * possible to program from python whether the callback + * is a waiting action + */ + class Action + { + public: + using Callback = std::function< + bool(Transaction *tran) + >; + + Action(Callback _cb, bool waiting) + : cb(_cb), _wait(waiting) + {} + virtual ~Action() {}; + + /* A basic action always returns true */ + virtual bool + run(Transaction *tran) + { + cb(tran); + return true; + } + + /** + * Returns true if the action dispatcher should break + * the dispatching loop once the action has been executed + */ + bool wait() const { return _wait; } + + protected: + Callback cb; + bool _wait; + }; + + /** + * Expectation: + * Will check for a specific condition and will warn if + * the condition is not met. + * The expectation is never a waiting action + */ + class Expectation : public Action + { + public: + Expectation(std::string exp_name, Callback _cb) + : Action(_cb, false), _name(exp_name) + {} + + bool run(Transaction *tran) override; + + std::string name() const { return _name; } + + private: + std::string _name; + }; + + /** + * Assertion: + * Will check for a specific condition and will fail if + * the condition is not met. + * The assertion is never a waiting action + */ + class Assertion : public Expectation + { + public: + Assertion(std::string exp_name, Callback _cb) + : Expectation(exp_name, _cb) + {} + + bool run(Transaction *tran) override; + }; + + using ActionPtr = std::unique_ptr; + using Actions = std::list; + + Transaction(const Transaction &rhs) = delete; + Transaction(ARM::CHI::Payload *pa, ARM::CHI::Phase &ph); + ~Transaction(); + + /** + * Registers the TlmGenerator in the transaction. This is + * used as a reference to the generator is required when + * injection the transaction + */ + void setGenerator(TlmGenerator *gen); + + std::string str() const; + + void inject(); + + /** + * Returns true if the transaction has failed, false + * otherwise + */ + bool failed() const; + + /** + * Returns true if the transaction has some + * registered callbacks, false otherwise + */ + bool hasCallbacks() const; + + /** + * Appends a callback to the list of actions + */ + void addCallback(ActionPtr &&action); + + /** + * Enters the dispatching loop and runs the callbacks + * in insertion order until a waiting callback is + * encountered (or if there is a failing assertion) + */ + void runCallbacks(); + + ARM::CHI::Payload* payload() const { return _payload; } + ARM::CHI::Phase& phase() { return _phase; } + + private: + Actions actions; + bool passed; + + TlmGenerator *parent; + ARM::CHI::Payload *_payload; + ARM::CHI::Phase _phase; + }; + + void scheduleTransaction(Tick when, Transaction *tr); + + protected: + struct TransactionEvent : public Event + { + public: + struct Compare + { + bool + operator()(const TransactionEvent *lhs, + const TransactionEvent *rhs) + { + return lhs->when < rhs->when; + } + }; + + TransactionEvent(Transaction *_transaction, + Tick _when) + : Event(), transaction(_transaction), when(_when) + {} + + void process() override; + + const char* + description() const override + { + return "CHI Transaction event"; + } + + Transaction *transaction; + Tick when; + }; + + void inject(Transaction *transaction); + void recv(ARM::CHI::Payload *payload, ARM::CHI::Phase *phase); + void passFailCheck(); + + protected: + /** cpuId to mimic the behaviour of a CPU */ + uint8_t cpuId; + + using SchedulingQueue = std::priority_queue, + TransactionEvent::Compare>; + + /** PQ of transactions whose injection needs to be scheduled */ + SchedulingQueue scheduledTransactions; + + /** Map of pending (injected) transactions indexed by the txn_id */ + std::unordered_map pendingTransactions; + + /** Pointer to the CHI-tlm controller */ + CacheController *controller; +}; + +} // namespace tlm::chi + +} // namespace gem5 + +#endif // __MEM_RUBY_PROTOCOL_CHI_TLM_GENERATOR_HH__ diff --git a/src/mem/ruby/protocol/chi/tlm/tlm_chi.py b/src/mem/ruby/protocol/chi/tlm/tlm_chi.py index 7e874dfd16..af158c3917 100644 --- a/src/mem/ruby/protocol/chi/tlm/tlm_chi.py +++ b/src/mem/ruby/protocol/chi/tlm/tlm_chi.py @@ -34,4 +34,14 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import _m5.tlm_chi +import _m5.tlm_chi_gen from _m5.tlm_chi import * +from _m5.tlm_chi_gen import * + + +def expect_equal(received, expected): + if received != expected: + print(f"Comparison mismatch. Received:{received}, Expected:{expected}") + return False + else: + return True diff --git a/src/mem/ruby/protocol/chi/tlm/tlm_chi_gen.cc b/src/mem/ruby/protocol/chi/tlm/tlm_chi_gen.cc new file mode 100644 index 0000000000..831b53082c --- /dev/null +++ b/src/mem/ruby/protocol/chi/tlm/tlm_chi_gen.cc @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2024 Arm Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * 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; + * neither the name of the copyright holders 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 + * OWNER 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. + */ + +#include + +#include "mem/ruby/protocol/chi/tlm/generator.hh" +// This is required by Transaction::expect +#include "pybind11/functional.h" +#include "python/pybind11/pybind.hh" +#include "sim/init.hh" + +namespace py = pybind11; + +using namespace ARM::CHI; + +namespace gem5 { + +namespace { + +void +tlm_chi_generator_pybind(pybind11::module_ &m_tlm_chi) +{ + auto tlm_chi_gen = m_tlm_chi.def_submodule("tlm_chi_gen"); + + using Action = tlm::chi::TlmGenerator::Transaction::Action; + using Expectation = tlm::chi::TlmGenerator::Transaction::Expectation; + using Assertion = tlm::chi::TlmGenerator::Transaction::Assertion; + using Callback = Action::Callback; + py::class_(tlm_chi_gen, "Transaction") + .def(py::init()) + .def("EXPECT_STR", + [] (tlm::chi::TlmGenerator::Transaction &self, + std::string name, + Callback cb) + { + self.addCallback(std::make_unique(name, cb)); + }) + .def("EXPECT", + [] (tlm::chi::TlmGenerator::Transaction &self, + py::function cb) + { + self.addCallback(std::make_unique( + cb.attr("__name__").cast(), + cb.cast())); + }) + .def("ASSERT", + [] (tlm::chi::TlmGenerator::Transaction &self, + std::string name, + Callback cb) + { + self.addCallback(std::make_unique(name, cb)); + }) + .def("DO", + [] (tlm::chi::TlmGenerator::Transaction &self, + Callback cb) + { + self.addCallback(std::make_unique(cb, false)); + }) + .def("DO_WAIT", + [] (tlm::chi::TlmGenerator::Transaction &self, + Callback cb) + { + self.addCallback(std::make_unique(cb, true)); + }) + .def("inject", &tlm::chi::TlmGenerator::Transaction::inject) + .def_property("phase", + &tlm::chi::TlmGenerator::Transaction::phase, + &tlm::chi::TlmGenerator::Transaction::phase) + ; +} + +EmbeddedPyBind embed_("tlm_chi_gen", &tlm_chi_generator_pybind, "tlm_chi"); + +} // namespace +} // namespace gem5