katang Posted April 5, 2018 Report Posted April 5, 2018 In my project, I have a base set of object (they should be synthesized, i.e optimized for speed and footprint) and a subclassed set of objects, which are for visualization, testing, demonstration etc. (i.e. optimized for usability). The two sets must have the same functionality concerning the base object (of course). In the MWE below, I am using a 'StandAlone' mode (synthesis only), using a logic variable. The 'business logic' is completely comprised in the base modules. The MWE below produces the following output: MWEbase standalone MWEbase created MWE starting MWEbase created MWE created Initialized MWEbase Initialized MWEbase Initialized MWE MWE waiting: MWE MWEbase waiting: MWEbase MWE terminated My questions: 1./ Any better idea to implement what I want to do (or any points against) 2./ The dynamic_cast<MWE*>(MWEbase::getME()) seems to be safe for me: although the pointer is of type base class, the object it points to is of derived class, and without casting (if used in standalone mode by the base object) it points to the right object. Any points against doing so? (or better idea, which avoids duplicating code and not error-prone)? 3./ BTW: is there any standard synthesizable way of using addresses of object (like cores in a processor)? 4./ It looks like that a virtual function of the base object registered with SystemC, does not work (from SystemC point of view: despite that Initialize_method is virtual, the registered in the base object code runs also from the derived class). What is exactly the case with registering a virtual function? (Is it dangerous, can be repeated in the derived class, ???) #ifndef MVE_H #define MWE_H #include <systemc> #include <iostream> SC_MODULE(MWEbase) { public: MWEbase(sc_core::sc_module_name nm, bool StandAlone = true); SC_HAS_PROCESS(MWEbase); virtual ~MWEbase(void); virtual void Initialize_method(void); virtual MWEbase* getME(void){return this;} void setMy(bool B){mMy = B;} void print_thread(void); sc_core::sc_event m_request; sc_core::sc_event m_inited; protected: bool mMy; MWEbase* mME; }; class MWE : public MWEbase { public: MWE(sc_core::sc_module_name nm); SC_HAS_PROCESS(MWE); virtual ~MWE(void); virtual void Initialize_method(void); virtual MWEbase* getME(void){return dynamic_cast<MWE*>(MWEbase::getME());} void print_thread(void); }; #endif // MWE_H #include "MWE.h" using namespace sc_core; // This is for synthesis MWEbase::MWEbase(sc_core::sc_module_name nm, bool StandAlone) : sc_core::sc_module(nm) { if(StandAlone) { mME = this; SC_THREAD(print_thread); sensitive << m_request; std::cerr << "MWEbase standalone\n"; } SC_METHOD(Initialize_method); std::cerr << "MWEbase created\n"; } MWEbase::~MWEbase(void){} // This is for simulation MWE::MWE(sc_core::sc_module_name nm) : MWEbase(nm,false){ mME = this; SC_THREAD(print_thread); sensitive << m_request; // SC_METHOD(Initialize_method); std::cerr << "MWE created\n"; } MWE::~MWE(void){} void MWEbase::print_thread(void){ wait(m_inited); while(true) { std::cerr << "MWEbase waiting: " << getME()->name() << '\n'; wait(m_request); } std::cerr << "This is MWEbase\n"; } void MWE::print_thread(void){ wait(m_inited); while(true) { std::cerr << "MWE waiting: " << getME()->name() << '\n'; wait(m_request); } std::cerr << "This is MWE\n"; } void MWEbase::Initialize_method(void) { m_request.notify(SC_ZERO_TIME); std::cerr << "Initialized MWEbase\n"; m_inited.notify(SC_ZERO_TIME); } void MWE::Initialize_method(void) { MWEbase::Initialize_method(); m_request.notify(SC_ZERO_TIME); std::cerr << "Initialized MWE\n"; m_inited.notify(SC_ZERO_TIME); } #include <systemc> #include "MWE.h" using namespace sc_core; int sc_main(int argc, char* argv[]) { sc_set_time_resolution(1,SC_NS); MWEbase MyMWEbase("MWEbase"); std::cerr << "MWE starting\n"; MWE MyMWE("MWE"); sc_start(); std::cerr << "MWE example terminated\n"; if (not sc_end_of_simulation_invoked()) sc_stop(); return 0; Quote
Eyck Posted April 5, 2018 Report Posted April 5, 2018 Hi katang, I cannot comment on 3./ but item 1./ and 2./ (dynamic_cast) is generally fine (at least from a simulation point of view). Wrt. to item 4./ this is a C++ mechanism which you do not really obey. If you construct the base class the virtual function pointer in the vtable of the class point to MWEbase::Initialize_method(). Hence you register the pointer to this method with the SystemC kernel. But this is easy to work around. Basically you register a dispatch function with the SystemC kernel which calls then the virtual function: void Dispatch_initialize_method(void) { Initialize_method();} virtual Initialize_method(void); In you constructor you register this function then: // This is for synthesis MWEbase::MWEbase(sc_core::sc_module_name nm, bool StandAlone) : sc_core::sc_module(nm) { if(StandAlone) { mME = this; SC_THREAD(print_thread); sensitive << m_request; std::cerr << "MWEbase standalone\n"; } SC_METHOD(Dispatch_initialize_method); std::cerr << "MWEbase created\n"; } This way the call to Initialize_method() will be resolved by runtime polymorphism (the vable mechanism) and the call goes to the correct function. Best regards Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.