blob: c5905bc592e5e566d1b37de1ac55485e4b94fdb6 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
#include <systemc>
#include "utils.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<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;
}
|