Jump to content
katang

Registering a virtual function with SystemC

Recommended Posts

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;

 

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×