blob: 16ddc066e24edd143ea25f334c57a8216519ca50 (
plain) (
tree)
|
|
#include <systemc>
#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 {
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<msg_if> 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<msg_if> 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;
}
|