From f396fab26611d6107e223a6a3f41c9dff3e2ee9e Mon Sep 17 00:00:00 2001 From: Johannes Stoelp Date: Sun, 27 Aug 2023 21:18:53 +0200 Subject: move sources into src/ subdir --- CMakeLists.txt | 2 +- Makefile | 6 +-- browse.cc | 74 -------------------------- event.cc | 140 -------------------------------------------------- minimal_socket.cc | 122 ------------------------------------------- sc_export.cc | 76 --------------------------- sc_export2.cc | 108 -------------------------------------- src/browse.cc | 74 ++++++++++++++++++++++++++ src/event.cc | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/minimal_socket.cc | 122 +++++++++++++++++++++++++++++++++++++++++++ src/sc_export.cc | 76 +++++++++++++++++++++++++++ src/sc_export2.cc | 108 ++++++++++++++++++++++++++++++++++++++ src/utils.h | 32 ++++++++++++ utils.h | 32 ------------ 14 files changed, 556 insertions(+), 556 deletions(-) delete mode 100644 browse.cc delete mode 100644 event.cc delete mode 100644 minimal_socket.cc delete mode 100644 sc_export.cc delete mode 100644 sc_export2.cc create mode 100644 src/browse.cc create mode 100644 src/event.cc create mode 100644 src/minimal_socket.cc create mode 100644 src/sc_export.cc create mode 100644 src/sc_export2.cc create mode 100644 src/utils.h delete mode 100644 utils.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 373f414..8e3d7fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,6 @@ find_package(SystemCLanguage CONFIG REQUIRED) set (CMAKE_CXX_STANDARD ${SystemC_CXX_STANDARD} CACHE STRING "C++ standard to build all targets.") foreach (X IN ITEMS event sc_export sc_export2 minimal_socket browse) - add_executable(${X} ${X}.cc) + add_executable(${X} src/${X}.cc) target_link_libraries(${X} SystemC::systemc) endforeach() diff --git a/Makefile b/Makefile index f22fbd0..3631e55 100644 --- a/Makefile +++ b/Makefile @@ -3,8 +3,8 @@ export CXX = clang++ export SYSTEMC_HOME := $(PWD)/INSTALL -SRCS = $(wildcard *.cc) -BINS = $(SRCS:%.cc=BUILD/UTIL/%) +SRCS = $(wildcard src/*.cc) +BINS = $(SRCS:src/%.cc=BUILD/PLAYGROUND/%) # -- SYSTEMC UTILS ------------------------------------------------------------- @@ -45,7 +45,7 @@ systemc: # -- UTIL ---------------------------------------------------------------------- fmt: - clang-format -i *.cc *.h + clang-format -i src/*.cc src/*.h # -- CLEAN --------------------------------------------------------------------- diff --git a/browse.cc b/browse.cc deleted file mode 100644 index afc132e..0000000 --- a/browse.cc +++ /dev/null @@ -1,74 +0,0 @@ -#include -#include "utils.h" - -using sc_core::sc_module; -using sc_core::sc_module_name; -using sc_core::sc_object; - -struct leaf_a : public sc_module { - explicit leaf_a(sc_module_name nm) : sc_module(nm) {} -}; - -struct leaf_b : public sc_module { - explicit leaf_b(sc_module_name nm) : sc_module(nm) {} -}; - -struct processor : public sc_module { - explicit processor(sc_module_name nm) : sc_module(nm), m_a("a"), m_b("b") {} - - leaf_a m_a; - leaf_b m_b; -}; - -struct memory : public sc_module { - explicit memory(sc_module_name nm) : sc_module(nm), m_a("a") {} - - leaf_a m_a; -}; - -struct soc : public sc_module { - explicit soc(sc_module_name nm) - : sc_module(nm), - m_mem0{"mem0"}, - m_mem1{"mem1"}, - m_mem2{"mem2"}, - m_mem3{"mem3"}, - m_proc0{"proc0"}, - m_proc1{"proc1"} {} - - memory m_mem0, m_mem1, m_mem2, m_mem3; - processor m_proc0, m_proc1; -}; - -// -- WALKER ------------------------------------------------------------------- - -void walk(const std::vector& objs, unsigned indent = 0) { - for (const auto* obj : objs) { - if (indent) { - printf("%*c", indent, ' '); - } - printf("BASENAME=" YELLOW "%s" RESET " NAME=" MAGENTA "%s" RESET - " HAS_PARENT=%d\n", - obj->basename(), obj->name(), obj->get_parent_object() != nullptr); - - walk(obj->get_child_objects(), indent + 2); - } -} - -// -- SC_MAIN ------------------------------------------------------------------ - -extern "C" int sc_main(int, char*[]) { - soc s("soc"); - - walk(sc_core::sc_get_top_level_objects()); - - const auto* obj = sc_core::sc_find_object("soc.mem0"); - if (obj != nullptr) { - puts(obj->name()); - } - - std::cout << sc_core::sc_hierarchical_name_exists("soc") << std::endl; - std::cout << sc_core::sc_hierarchical_name_exists(obj, "a") << std::endl; - - return 0; -} diff --git a/event.cc b/event.cc deleted file mode 100644 index 96750bc..0000000 --- a/event.cc +++ /dev/null @@ -1,140 +0,0 @@ -#include -#include "utils.h" - -using sc_core::sc_event; -using sc_core::sc_module; -using sc_core::sc_module_name; -using sc_core::SC_NS; -using sc_core::sc_start; -using sc_core::sc_time; -using sc_core::SC_ZERO_TIME; - -// -- MOD_METHOD --------------------------------------------------------------- - -struct mod_method : public sc_module { - SC_HAS_PROCESS(mod_method); - - explicit mod_method(sc_module_name nm) : sc_module(nm) { - SC_METHOD(ev_method); - // STATIC sensitivity for ev_method, the METHOD will become RUNNABLE when - // the event is notified. - sensitive << m_method_event; - // DONT run method initially at time 0s, only after it is triggered. - // By default SC_METHODs are made RUNNABLE at time 0s. - dont_initialize(); - - // Helper to drive the method example. - SC_THREAD(run_method); - } - - private: - sc_event m_method_event; - - void ev_method() { - // No calls to wait() in METHODS. - // Methods are triggered by static sensitivity or dynamic sensitivity. - - CLOGM(GREEN, "triggered by_static_event_not_next_trigger=%d timed_out=%d", - m_method_event.triggered(), timed_out()); - - if (m_method_event.triggered()) { - // Create DYNAMIC sensitivity list, either by time or event. - // The DYNAMIC sensitivity OVERRIDES the STATIC sensitivity, therefore if - // the event is not listed here, the method will only be triggered by the - // TIME value no matter if the EVENT (static sensitivity) is triggered. - next_trigger(5000, SC_NS, m_method_event); - } - } - - void run_method() { - // Notify event in the future. - CLOGM(YELLOW, "TIMED NOTIFY"); - m_method_event.notify(100, SC_NS); - - wait(200, SC_NS); - - // Notify event in the next delta cycle. - CLOGM(YELLOW, "DELTA NOTIFY"); - m_method_event.notify(SC_ZERO_TIME); - - wait(200, SC_NS); - - // Notify event in the current delta cycle. - CLOGM(YELLOW, "IMMEDIATE NOTIFY"); - m_method_event.notify(); - - wait(200, SC_NS); - } -}; - -// -- MOD_THREAD --------------------------------------------------------------- - -struct mod_thread : public sc_module { - SC_HAS_PROCESS(mod_thread); - - explicit mod_thread(sc_module_name nm) : sc_module(nm) { - SC_THREAD(ev_thread); - // STATIC sensitivity for ev_thread. - sensitive << m_thread_event; - - // Helper to drive the example and drive the simulator. - SC_THREAD(run_thread); - } - - private: - sc_event m_thread_event; - - void ev_thread() { - // WAIT on STATIC sensitivity event. - wait(); - - while (true) { - CLOGM(CYAN, "WAIT TIMED or EVENT"); - // Create DYNAMIC sensitivity list, WAIT on either TIMEOUT or EVENT. - wait(sc_time(2000, SC_NS), m_thread_event); - CLOGM(CYAN, "done by_event_not_time=%d timed_out=%d", - m_thread_event.triggered(), timed_out()); - - CLOGM(CYAN, "WAIT STATIC SENSITIVITY"); - // WAIT on static sensitivity trigger. - wait(); - CLOGM(CYAN, "done"); - } - } - - void run_thread() { - // Some initial wait, to run at different time than the method example. - wait(10000, SC_NS); - m_thread_event.notify(SC_ZERO_TIME); - - CLOGM(MAGENTA, "big TIMED WAIT -> should timeout thread"); - wait(10000, SC_NS); - - CLOGM(MAGENTA, "TIMED NOTIFY"); - m_thread_event.notify(100, SC_NS); - - wait(1000, SC_NS); - - CLOGM(MAGENTA, "TIMED NOTIFY"); - m_thread_event.notify(200, SC_NS); - - wait(1000, SC_NS); - - CLOGM(MAGENTA, "DELTA NOTIFY"); - m_thread_event.notify(SC_ZERO_TIME); - } -}; - -// -- SC_MAIN ------------------------------------------------------------------ - -extern "C" int sc_main(int, char*[]) { - // timed_out() is deprecated, but it is just used for visualization here. - sc_core::sc_report_handler::set_actions("/IEEE_Std_1666/deprecated", - sc_core::SC_DO_NOTHING); - - mod_method method("method"); - mod_thread thread("thread"); - - sc_start(); - return 0; -} diff --git a/minimal_socket.cc b/minimal_socket.cc deleted file mode 100644 index 7fe7f38..0000000 --- a/minimal_socket.cc +++ /dev/null @@ -1,122 +0,0 @@ -#include -#include "utils.h" - -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_NS; -using sc_core::sc_port; - -// -- INTERFACES --------------------------------------------------------------- - -struct fwd_if : sc_interface { - virtual void fwd(const char* msg) = 0; -}; - -struct bwd_if : sc_interface { - virtual void bwd(const char* msg) = 0; -}; - -// -- INITIATOR SOCKET --------------------------------------------------------- - -// An initiator socket provides its owner access to a FWD_IF implementation. The -// initiator socket itself must be bound against a BWD_IF implementation, -// offering the BWD_IF implementation to the target socket that can be bound -// against the initiator socket. -// -// Effectively the initiator socket is a sc_port / sc_export pair, using the -// sc_port to access the FWD_IF and the sc_export to offer the BWD_IF -// implementation. - -struct initiator_socket : sc_export { - sc_port p_fwd; - - fwd_if* operator->() { - return p_fwd.operator->(); - } -}; - -// -- TARGET SOCKET ------------------------------------------------------------ - -// A target socket provides its owner access to a BWD_IF implementation. The -// target socket itself must be bound against a FWD_IF implementation, -// offering the FWD_IF implementation to the initiator socket that can be bound -// against the target socket. -// -// Effectively the target socket is a sc_port / sc_export pair, using the -// sc_port to access the BWD_IF and the sc_export to offer the FWD_IF -// implementation. - -struct target_socket : sc_export { - sc_port p_bwd; - - void bind(initiator_socket& init) { - // Bind the sc_port / sc_export pairs between the initiator and target - // socket. - - // Initiator:sc_port -> Target:sc_export. - init.p_fwd(*this); - - // Target:sc_port -> Initiator:sc_export. - p_bwd(init); - } - - bwd_if* operator->() { - return p_bwd.operator->(); - } -}; - -// -- INITIATOR ---------------------------------------------------------------- - -struct initiator : public sc_module, public bwd_if { - SC_HAS_PROCESS(initiator); - - initiator_socket p_sock; - - explicit initiator(sc_module_name nm) : sc_module(std::move(nm)) { - p_sock(*this); - SC_THREAD(work); - } - - private: - virtual void bwd(const char* msg) override { - LOGM("%s", msg); - } - - void work() { - sc_core::wait(10, SC_NS); - p_sock->fwd("moose"); - } -}; - -// -- TARGET ------------------------------------------------------------------- - -struct target : public sc_module, public fwd_if { - SC_HAS_PROCESS(target); - - target_socket p_sock; - - explicit target(sc_module_name nm) : sc_module(std::move(nm)) { - p_sock(*this); - } - - private: - virtual void fwd(const char* msg) override { - LOGM("%s", msg); - p_sock->bwd("meeh"); - } -}; - -// -- SC_MAIN ------------------------------------------------------------------ - -extern "C" int sc_main(int, char*[]) { - initiator I("initiator"); - target T("target"); - - // Bind the initiator and target sockets. - T.p_sock.bind(I.p_sock); - - sc_core::sc_start(); - return 0; -} diff --git a/sc_export.cc b/sc_export.cc deleted file mode 100644 index 7acca58..0000000 --- a/sc_export.cc +++ /dev/null @@ -1,76 +0,0 @@ -#include -#include "utils.h" - -using sc_core::sc_export; -using sc_core::sc_in; -using sc_core::sc_module; -using sc_core::sc_module_name; -using sc_core::SC_NS; -using sc_core::sc_signal; -using sc_core::sc_signal_inout_if; - -// -- CLOCK_GEN ---------------------------------------------------------------- - -struct clock_gen : public sc_module { - SC_HAS_PROCESS(clock_gen); - - explicit clock_gen(sc_module_name nm, unsigned period_ns = 20) - : sc_module(nm), m_half_period(period_ns / 2) { - assert(period_ns == m_half_period * 2); - - // Bind sc_signal (clk) against export. - p_clk(m_clk); - - SC_METHOD(tick); - } - - // Export to expose sc_signal (clk) outside this module. - sc_export> p_clk; - - private: - // Implementation of sc_signal_inout_if. - sc_signal m_clk; - - const unsigned m_half_period; - - void tick() { - m_clk.write(!m_clk.read()); - next_trigger(m_half_period, SC_NS); - } -}; - -// -- TICKTOCK ----------------------------------------------------------------- - -struct ticktock : public sc_module { - SC_HAS_PROCESS(ticktock); - - explicit ticktock(sc_module_name nm) : sc_module(nm) { - SC_METHOD(handle_clk); - sensitive << p_clk; - dont_initialize(); - } - - // In port, where sc_in is just a sc_port>. - sc_in p_clk; - - private: - void handle_clk() { - if (p_clk.read()) { - LOGM("TICK"); - } else { - LOGM("TOCK"); - } - } -}; - -// -- SC_MAIN ------------------------------------------------------------------ - -extern "C" int sc_main(int, char*[]) { - clock_gen clk("clk"); - ticktock tiktok{"listen"}; - - tiktok.p_clk(clk.p_clk); - - sc_start(200, SC_NS); - return 0; -} diff --git a/sc_export2.cc b/sc_export2.cc deleted file mode 100644 index c5905bc..0000000 --- a/sc_export2.cc +++ /dev/null @@ -1,108 +0,0 @@ -#include -#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 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; -} diff --git a/src/browse.cc b/src/browse.cc new file mode 100644 index 0000000..afc132e --- /dev/null +++ b/src/browse.cc @@ -0,0 +1,74 @@ +#include +#include "utils.h" + +using sc_core::sc_module; +using sc_core::sc_module_name; +using sc_core::sc_object; + +struct leaf_a : public sc_module { + explicit leaf_a(sc_module_name nm) : sc_module(nm) {} +}; + +struct leaf_b : public sc_module { + explicit leaf_b(sc_module_name nm) : sc_module(nm) {} +}; + +struct processor : public sc_module { + explicit processor(sc_module_name nm) : sc_module(nm), m_a("a"), m_b("b") {} + + leaf_a m_a; + leaf_b m_b; +}; + +struct memory : public sc_module { + explicit memory(sc_module_name nm) : sc_module(nm), m_a("a") {} + + leaf_a m_a; +}; + +struct soc : public sc_module { + explicit soc(sc_module_name nm) + : sc_module(nm), + m_mem0{"mem0"}, + m_mem1{"mem1"}, + m_mem2{"mem2"}, + m_mem3{"mem3"}, + m_proc0{"proc0"}, + m_proc1{"proc1"} {} + + memory m_mem0, m_mem1, m_mem2, m_mem3; + processor m_proc0, m_proc1; +}; + +// -- WALKER ------------------------------------------------------------------- + +void walk(const std::vector& objs, unsigned indent = 0) { + for (const auto* obj : objs) { + if (indent) { + printf("%*c", indent, ' '); + } + printf("BASENAME=" YELLOW "%s" RESET " NAME=" MAGENTA "%s" RESET + " HAS_PARENT=%d\n", + obj->basename(), obj->name(), obj->get_parent_object() != nullptr); + + walk(obj->get_child_objects(), indent + 2); + } +} + +// -- SC_MAIN ------------------------------------------------------------------ + +extern "C" int sc_main(int, char*[]) { + soc s("soc"); + + walk(sc_core::sc_get_top_level_objects()); + + const auto* obj = sc_core::sc_find_object("soc.mem0"); + if (obj != nullptr) { + puts(obj->name()); + } + + std::cout << sc_core::sc_hierarchical_name_exists("soc") << std::endl; + std::cout << sc_core::sc_hierarchical_name_exists(obj, "a") << std::endl; + + return 0; +} diff --git a/src/event.cc b/src/event.cc new file mode 100644 index 0000000..96750bc --- /dev/null +++ b/src/event.cc @@ -0,0 +1,140 @@ +#include +#include "utils.h" + +using sc_core::sc_event; +using sc_core::sc_module; +using sc_core::sc_module_name; +using sc_core::SC_NS; +using sc_core::sc_start; +using sc_core::sc_time; +using sc_core::SC_ZERO_TIME; + +// -- MOD_METHOD --------------------------------------------------------------- + +struct mod_method : public sc_module { + SC_HAS_PROCESS(mod_method); + + explicit mod_method(sc_module_name nm) : sc_module(nm) { + SC_METHOD(ev_method); + // STATIC sensitivity for ev_method, the METHOD will become RUNNABLE when + // the event is notified. + sensitive << m_method_event; + // DONT run method initially at time 0s, only after it is triggered. + // By default SC_METHODs are made RUNNABLE at time 0s. + dont_initialize(); + + // Helper to drive the method example. + SC_THREAD(run_method); + } + + private: + sc_event m_method_event; + + void ev_method() { + // No calls to wait() in METHODS. + // Methods are triggered by static sensitivity or dynamic sensitivity. + + CLOGM(GREEN, "triggered by_static_event_not_next_trigger=%d timed_out=%d", + m_method_event.triggered(), timed_out()); + + if (m_method_event.triggered()) { + // Create DYNAMIC sensitivity list, either by time or event. + // The DYNAMIC sensitivity OVERRIDES the STATIC sensitivity, therefore if + // the event is not listed here, the method will only be triggered by the + // TIME value no matter if the EVENT (static sensitivity) is triggered. + next_trigger(5000, SC_NS, m_method_event); + } + } + + void run_method() { + // Notify event in the future. + CLOGM(YELLOW, "TIMED NOTIFY"); + m_method_event.notify(100, SC_NS); + + wait(200, SC_NS); + + // Notify event in the next delta cycle. + CLOGM(YELLOW, "DELTA NOTIFY"); + m_method_event.notify(SC_ZERO_TIME); + + wait(200, SC_NS); + + // Notify event in the current delta cycle. + CLOGM(YELLOW, "IMMEDIATE NOTIFY"); + m_method_event.notify(); + + wait(200, SC_NS); + } +}; + +// -- MOD_THREAD --------------------------------------------------------------- + +struct mod_thread : public sc_module { + SC_HAS_PROCESS(mod_thread); + + explicit mod_thread(sc_module_name nm) : sc_module(nm) { + SC_THREAD(ev_thread); + // STATIC sensitivity for ev_thread. + sensitive << m_thread_event; + + // Helper to drive the example and drive the simulator. + SC_THREAD(run_thread); + } + + private: + sc_event m_thread_event; + + void ev_thread() { + // WAIT on STATIC sensitivity event. + wait(); + + while (true) { + CLOGM(CYAN, "WAIT TIMED or EVENT"); + // Create DYNAMIC sensitivity list, WAIT on either TIMEOUT or EVENT. + wait(sc_time(2000, SC_NS), m_thread_event); + CLOGM(CYAN, "done by_event_not_time=%d timed_out=%d", + m_thread_event.triggered(), timed_out()); + + CLOGM(CYAN, "WAIT STATIC SENSITIVITY"); + // WAIT on static sensitivity trigger. + wait(); + CLOGM(CYAN, "done"); + } + } + + void run_thread() { + // Some initial wait, to run at different time than the method example. + wait(10000, SC_NS); + m_thread_event.notify(SC_ZERO_TIME); + + CLOGM(MAGENTA, "big TIMED WAIT -> should timeout thread"); + wait(10000, SC_NS); + + CLOGM(MAGENTA, "TIMED NOTIFY"); + m_thread_event.notify(100, SC_NS); + + wait(1000, SC_NS); + + CLOGM(MAGENTA, "TIMED NOTIFY"); + m_thread_event.notify(200, SC_NS); + + wait(1000, SC_NS); + + CLOGM(MAGENTA, "DELTA NOTIFY"); + m_thread_event.notify(SC_ZERO_TIME); + } +}; + +// -- SC_MAIN ------------------------------------------------------------------ + +extern "C" int sc_main(int, char*[]) { + // timed_out() is deprecated, but it is just used for visualization here. + sc_core::sc_report_handler::set_actions("/IEEE_Std_1666/deprecated", + sc_core::SC_DO_NOTHING); + + mod_method method("method"); + mod_thread thread("thread"); + + sc_start(); + return 0; +} diff --git a/src/minimal_socket.cc b/src/minimal_socket.cc new file mode 100644 index 0000000..7fe7f38 --- /dev/null +++ b/src/minimal_socket.cc @@ -0,0 +1,122 @@ +#include +#include "utils.h" + +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_NS; +using sc_core::sc_port; + +// -- INTERFACES --------------------------------------------------------------- + +struct fwd_if : sc_interface { + virtual void fwd(const char* msg) = 0; +}; + +struct bwd_if : sc_interface { + virtual void bwd(const char* msg) = 0; +}; + +// -- INITIATOR SOCKET --------------------------------------------------------- + +// An initiator socket provides its owner access to a FWD_IF implementation. The +// initiator socket itself must be bound against a BWD_IF implementation, +// offering the BWD_IF implementation to the target socket that can be bound +// against the initiator socket. +// +// Effectively the initiator socket is a sc_port / sc_export pair, using the +// sc_port to access the FWD_IF and the sc_export to offer the BWD_IF +// implementation. + +struct initiator_socket : sc_export { + sc_port p_fwd; + + fwd_if* operator->() { + return p_fwd.operator->(); + } +}; + +// -- TARGET SOCKET ------------------------------------------------------------ + +// A target socket provides its owner access to a BWD_IF implementation. The +// target socket itself must be bound against a FWD_IF implementation, +// offering the FWD_IF implementation to the initiator socket that can be bound +// against the target socket. +// +// Effectively the target socket is a sc_port / sc_export pair, using the +// sc_port to access the BWD_IF and the sc_export to offer the FWD_IF +// implementation. + +struct target_socket : sc_export { + sc_port p_bwd; + + void bind(initiator_socket& init) { + // Bind the sc_port / sc_export pairs between the initiator and target + // socket. + + // Initiator:sc_port -> Target:sc_export. + init.p_fwd(*this); + + // Target:sc_port -> Initiator:sc_export. + p_bwd(init); + } + + bwd_if* operator->() { + return p_bwd.operator->(); + } +}; + +// -- INITIATOR ---------------------------------------------------------------- + +struct initiator : public sc_module, public bwd_if { + SC_HAS_PROCESS(initiator); + + initiator_socket p_sock; + + explicit initiator(sc_module_name nm) : sc_module(std::move(nm)) { + p_sock(*this); + SC_THREAD(work); + } + + private: + virtual void bwd(const char* msg) override { + LOGM("%s", msg); + } + + void work() { + sc_core::wait(10, SC_NS); + p_sock->fwd("moose"); + } +}; + +// -- TARGET ------------------------------------------------------------------- + +struct target : public sc_module, public fwd_if { + SC_HAS_PROCESS(target); + + target_socket p_sock; + + explicit target(sc_module_name nm) : sc_module(std::move(nm)) { + p_sock(*this); + } + + private: + virtual void fwd(const char* msg) override { + LOGM("%s", msg); + p_sock->bwd("meeh"); + } +}; + +// -- SC_MAIN ------------------------------------------------------------------ + +extern "C" int sc_main(int, char*[]) { + initiator I("initiator"); + target T("target"); + + // Bind the initiator and target sockets. + T.p_sock.bind(I.p_sock); + + sc_core::sc_start(); + return 0; +} diff --git a/src/sc_export.cc b/src/sc_export.cc new file mode 100644 index 0000000..7acca58 --- /dev/null +++ b/src/sc_export.cc @@ -0,0 +1,76 @@ +#include +#include "utils.h" + +using sc_core::sc_export; +using sc_core::sc_in; +using sc_core::sc_module; +using sc_core::sc_module_name; +using sc_core::SC_NS; +using sc_core::sc_signal; +using sc_core::sc_signal_inout_if; + +// -- CLOCK_GEN ---------------------------------------------------------------- + +struct clock_gen : public sc_module { + SC_HAS_PROCESS(clock_gen); + + explicit clock_gen(sc_module_name nm, unsigned period_ns = 20) + : sc_module(nm), m_half_period(period_ns / 2) { + assert(period_ns == m_half_period * 2); + + // Bind sc_signal (clk) against export. + p_clk(m_clk); + + SC_METHOD(tick); + } + + // Export to expose sc_signal (clk) outside this module. + sc_export> p_clk; + + private: + // Implementation of sc_signal_inout_if. + sc_signal m_clk; + + const unsigned m_half_period; + + void tick() { + m_clk.write(!m_clk.read()); + next_trigger(m_half_period, SC_NS); + } +}; + +// -- TICKTOCK ----------------------------------------------------------------- + +struct ticktock : public sc_module { + SC_HAS_PROCESS(ticktock); + + explicit ticktock(sc_module_name nm) : sc_module(nm) { + SC_METHOD(handle_clk); + sensitive << p_clk; + dont_initialize(); + } + + // In port, where sc_in is just a sc_port>. + sc_in p_clk; + + private: + void handle_clk() { + if (p_clk.read()) { + LOGM("TICK"); + } else { + LOGM("TOCK"); + } + } +}; + +// -- SC_MAIN ------------------------------------------------------------------ + +extern "C" int sc_main(int, char*[]) { + clock_gen clk("clk"); + ticktock tiktok{"listen"}; + + tiktok.p_clk(clk.p_clk); + + sc_start(200, SC_NS); + return 0; +} diff --git a/src/sc_export2.cc b/src/sc_export2.cc new file mode 100644 index 0000000..c5905bc --- /dev/null +++ b/src/sc_export2.cc @@ -0,0 +1,108 @@ +#include +#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 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; +} diff --git a/src/utils.h b/src/utils.h new file mode 100644 index 0000000..5584027 --- /dev/null +++ b/src/utils.h @@ -0,0 +1,32 @@ +#ifndef UTILS_H +#define UTILS_H + +#include + +#define LOG(FMT, ...) \ + do { \ + std::fprintf(stderr, "%10s | %4lld:%2lld | %10s | " FMT "\n", \ + sc_core::sc_time_stamp().to_string().c_str(), \ + sc_core::sc_delta_count(), \ + sc_core::sc_delta_count_at_current_time(), __FUNCTION__, \ + ##__VA_ARGS__); \ + } while (0) + +#define LOGM(FMT, ...) LOG("%12s | " FMT, name(), ##__VA_ARGS__) + +// -- COLOR LOGS --------------------------------------------------------------- + +#define RESET "\e[0m" +#define BLACK "\e[0;30m" +#define RED "\e[0;31m" +#define GREEN "\e[0;32m" +#define YELLOW "\e[0;33m" +#define BLUE "\e[0;34m" +#define MAGENTA "\e[0;35m" +#define CYAN "\e[0;36m" +#define WHITE "\e[0;37m" + +#define CLOG(COL, FMT, ...) LOG(COL FMT "\e[0m", ##__VA_ARGS__) +#define CLOGM(COL, FMT, ...) LOGM(COL FMT "\e[0m", ##__VA_ARGS__) + +#endif diff --git a/utils.h b/utils.h deleted file mode 100644 index 5584027..0000000 --- a/utils.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef UTILS_H -#define UTILS_H - -#include - -#define LOG(FMT, ...) \ - do { \ - std::fprintf(stderr, "%10s | %4lld:%2lld | %10s | " FMT "\n", \ - sc_core::sc_time_stamp().to_string().c_str(), \ - sc_core::sc_delta_count(), \ - sc_core::sc_delta_count_at_current_time(), __FUNCTION__, \ - ##__VA_ARGS__); \ - } while (0) - -#define LOGM(FMT, ...) LOG("%12s | " FMT, name(), ##__VA_ARGS__) - -// -- COLOR LOGS --------------------------------------------------------------- - -#define RESET "\e[0m" -#define BLACK "\e[0;30m" -#define RED "\e[0;31m" -#define GREEN "\e[0;32m" -#define YELLOW "\e[0;33m" -#define BLUE "\e[0;34m" -#define MAGENTA "\e[0;35m" -#define CYAN "\e[0;36m" -#define WHITE "\e[0;37m" - -#define CLOG(COL, FMT, ...) LOG(COL FMT "\e[0m", ##__VA_ARGS__) -#define CLOGM(COL, FMT, ...) LOGM(COL FMT "\e[0m", ##__VA_ARGS__) - -#endif -- cgit v1.2.3