#include #include "utils/log.h" // This file gives an example on how to define an own interface and use that // interface to communicate between two sc_modules. // // One module is the driver and accesses the interface via a sc_port and the // other module provides an implementation of the interface and exposes it via a // sc_export. // // The sc_port deref into the interface and therefore allows to directly call // any interface method on the sc_port via the operator->(). // // The sc_port and sc_export are then bound to connect the driver and the // implementer. The sc_export must additionally be bound against an interface // implementation. // // This example lays a foundation in understanding how TLM2 sockets work. using sc_core::sc_export; using sc_core::sc_interface; using sc_core::sc_module; using sc_core::sc_module_name; using sc_core::sc_port; // -- INTERFACE ---------------------------------------------------------------- struct msg_if : sc_interface { enum message { kHello, kPayload, kGoodbye, }; virtual void send(message) = 0; }; constexpr inline const char* to_str(msg_if::message msg) { switch (msg) { case msg_if::kHello: return "Hello"; case msg_if::kPayload: return "Payload"; case msg_if::kGoodbye: return "Goodbye"; } } // -- SENDER ------------------------------------------------------------------- struct sender : public sc_module { SC_HAS_PROCESS(sender); explicit sender(sc_module_name nm) : sc_module(nm) { SC_METHOD(do_protocol); } // A sc_port instantiated with the custom interface. The sc_port is used by // this module to access the interface implementation. sc_port p_msg; private: void do_protocol() { const auto send = [this](msg_if::message msg) { LOGM("%s", to_str(msg)); // sc_port derefs into msg_if via operator->(). p_msg->send(msg); }; // Send out some messages through the msg_if via the sc_port. send(msg_if::kHello); send(msg_if::kPayload); send(msg_if::kGoodbye); } }; // -- RECEIVER ----------------------------------------------------------------- struct receiver : public sc_module, public msg_if { explicit receiver(sc_module_name nm) : sc_module(nm) { // Bind the msg_if implementation against sc_export. p_msg(*this); } // A sc_export instantiated with the custom interface. The sc_export can be // bound against a sc_port (with the same interface), which effectively binds // the implementation behind the sc_export against the sc_port. sc_export p_msg; private: virtual void send(msg_if::message msg) override { LOGM("%s", to_str(msg)); } }; // -- SC_MAIN ------------------------------------------------------------------ extern "C" int sc_main(int, char*[]) { sender s("sender"); receiver r{"receiver"}; // Bind the sc_port and sc_export, such that the sender will invoke the msg_if // implemented by the receiver. s.p_msg(r.p_msg); sc_core::sc_start(); return 0; }