Jump to content
hakimelectronics

problem with call C from SystemC

Recommended Posts

I have a platform for native simulation, composed with sc_main.cpp, native_wrapper.cpp, native_wrapper.h, hardware.... I have to implement another CPU but I didn't find a method to make this.

Because extern "C" is needed since the software is compiled in C and is linked against native_wrapper.cpp, which is compiled in C++, for this, we call methods of soft in a this manner, using “NativeWrapper::get_instance()->method_name()”
below you can see code of sc_main.cpp, native_wrapper.cpp and native_wrapper.h.Thanks for your help

code for native_wrapper.h

#include "ensitlm.h"
#include "native_wrapper.h"

/* extern "C" is needed since the software is compiled in C and
 * is linked against native_wrapper.cpp, which is compiled in C++.
 */
extern "C" int __start();
extern "C" void __interrupt();

extern "C" void write_mem(uint32_t addr, uint32_t data) {
    //abort(); // TODO
    NativeWrapper::get_instance()->write_mem(addr, data);
     }

extern "C" unsigned int read_mem(uint32_t addr) {
    //abort(); // TODO
    return     NativeWrapper::get_instance()->read_mem(addr);
}

extern "C" void cpu_relax() {
    //abort(); // TODO    
    NativeWrapper::get_instance()->cpu_relax();
}

extern "C" void wait_for_irq() {
    //abort(); // TODO
    NativeWrapper::get_instance()->wait_for_irq();

}

NativeWrapper * NativeWrapper::get_instance() {
    static NativeWrapper * instance = NULL;
    if (!instance)
        instance = new NativeWrapper("native_wrapper");
    return instance;
}

NativeWrapper::NativeWrapper(sc_core::sc_module_name name) : sc_module(name),
                                 irq("irq")
{
    SC_THREAD(compute);
    SC_METHOD(interrupt_handler_internal);
    sensitive << irq ;
    dont_initialize();
}

void NativeWrapper::write_mem(unsigned int addr, unsigned int data)
{
    tlm::tlm_response_status stat = socket.write(addr, data);
}

unsigned int NativeWrapper::read_mem(unsigned int addr)
{
    //abort(); // TODO
    uint32_t localbuf;
    tlm::tlm_response_status stat = socket.read(addr,localbuf);
    return localbuf;
}

void NativeWrapper::cpu_relax()
{
    //abort(); // TODO
    wait(1000, sc_core::SC_MS); /* temps arbitraire */
}

void NativeWrapper::wait_for_irq()
{
    if (!interrupt) wait(interrupt_event);
       interrupt = false;
}

void NativeWrapper::compute()
{
    //abort(); // TODO
    __start();
}

void NativeWrapper::interrupt_handler_internal()
{
    interrupt = true; interrupt_event.notify();
    __interrupt();
}

and native_wrapper.h :

#ifndef NATIVEWRAPPER_H
#define NATIVEWRAPPER_H

#ifndef ENSITLM_H
#error Please include file "ensitlm.h"
#endif

SC_MODULE(NativeWrapper) {

    ensitlm::initiator_socket<NativeWrapper> socket;
        sc_core::sc_in<bool>                            irq;
private:
        SC_CTOR(NativeWrapper);
public:
    /*
       We use a singleton here. This is a limitation since it
       doesn't allow multiple NativeWrapper instances (multiple CPU
       in the platform), but it considerably reduces the
       complexity of Makefiles, hal.h, ...
    */
    static NativeWrapper * get_instance();

        void write_mem(unsigned int addr, unsigned int data);
        unsigned int read_mem(unsigned int addr);   
        void cpu_relax();
        void wait_for_irq();
        void compute();
        void interrupt_handler_internal();
        bool              interrupt;
        sc_core::sc_event interrupt_event;
};

#endif

sc_main.cpp

#include "ensitlm.h"
#include "native_wrapper.h"
#include "memory.h"
#include "bus.h"
#include "timer.h"
#include "vga.h"
#include "intc.h"
#include "gpio.h"

int sc_main(int, char**)
{
    NativeWrapper& cpu = *NativeWrapper::get_instance();
    Memory memory("Memory", 0x00100000);
    Bus bus("bus");
    TIMER timer("timer", sc_core::sc_time(20, sc_core::SC_NS));
    Vga vga("vga");
    Intc intc("intc");
    Gpio gpio("gpio");
......



Share this post


Link to post
Share on other sites

 

I have a platform for native simulation, composed with sc_main.cpp, native_wrapper.cpp, native_wrapper.h, hardware.... I have to implement another CPU but I didn't find a method to make this.

Because extern "C" is needed since the software is compiled in C and is linked against native_wrapper.cpp, which is compiled in C++, for this, we call methods of soft in a this manner, using “NativeWrapper::get_instance()->method_name()”
below you can see code of sc_main.cpp, native_wrapper.cpp and native_wrapper.h.Thanks for your help

code for native_wrapper.h

#include "ensitlm.h"
#include "native_wrapper.h"

/* extern "C" is needed since the software is compiled in C and
 * is linked against native_wrapper.cpp, which is compiled in C++.
 */
extern "C" int __start();
extern "C" void __interrupt();

extern "C" void write_mem(uint32_t addr, uint32_t data) {
    //abort(); // TODO
    NativeWrapper::get_instance()->write_mem(addr, data);
     }

extern "C" unsigned int read_mem(uint32_t addr) {
    //abort(); // TODO
    return     NativeWrapper::get_instance()->read_mem(addr);
}

extern "C" void cpu_relax() {
    //abort(); // TODO    
    NativeWrapper::get_instance()->cpu_relax();
}

extern "C" void wait_for_irq() {
    //abort(); // TODO
    NativeWrapper::get_instance()->wait_for_irq();

}

NativeWrapper * NativeWrapper::get_instance() {
    static NativeWrapper * instance = NULL;
    if (!instance)
        instance = new NativeWrapper("native_wrapper");
    return instance;
}

NativeWrapper::NativeWrapper(sc_core::sc_module_name name) : sc_module(name),
                                 irq("irq")
{
    SC_THREAD(compute);
    SC_METHOD(interrupt_handler_internal);
    sensitive << irq ;
    dont_initialize();
}

void NativeWrapper::write_mem(unsigned int addr, unsigned int data)
{
    tlm::tlm_response_status stat = socket.write(addr, data);
}

unsigned int NativeWrapper::read_mem(unsigned int addr)
{
    //abort(); // TODO
    uint32_t localbuf;
    tlm::tlm_response_status stat = socket.read(addr,localbuf);
    return localbuf;
}

void NativeWrapper::cpu_relax()
{
    //abort(); // TODO
    wait(1000, sc_core::SC_MS); /* temps arbitraire */
}

void NativeWrapper::wait_for_irq()
{
    if (!interrupt) wait(interrupt_event);
       interrupt = false;
}

void NativeWrapper::compute()
{
    //abort(); // TODO
    __start();
}

void NativeWrapper::interrupt_handler_internal()
{
    interrupt = true; interrupt_event.notify();
    __interrupt();
}

and native_wrapper.h :

#ifndef NATIVEWRAPPER_H
#define NATIVEWRAPPER_H

#ifndef ENSITLM_H
#error Please include file "ensitlm.h"
#endif

SC_MODULE(NativeWrapper) {

    ensitlm::initiator_socket<NativeWrapper> socket;
        sc_core::sc_in<bool>                            irq;
private:
        SC_CTOR(NativeWrapper);
public:
    /*
       We use a singleton here. This is a limitation since it
       doesn't allow multiple NativeWrapper instances (multiple CPU
       in the platform), but it considerably reduces the
       complexity of Makefiles, hal.h, ...
    */
    static NativeWrapper * get_instance();

        void write_mem(unsigned int addr, unsigned int data);
        unsigned int read_mem(unsigned int addr);   
        void cpu_relax();
        void wait_for_irq();
        void compute();
        void interrupt_handler_internal();
        bool              interrupt;
        sc_core::sc_event interrupt_event;
};

#endif

sc_main.cpp

#include "ensitlm.h"
#include "native_wrapper.h"
#include "memory.h"
#include "bus.h"
#include "timer.h"
#include "vga.h"
#include "intc.h"
#include "gpio.h"

int sc_main(int, char**)
{
    NativeWrapper& cpu = *NativeWrapper::get_instance();
    Memory memory("Memory", 0x00100000);
    Bus bus("bus");
    TIMER timer("timer", sc_core::sc_time(20, sc_core::SC_NS));
    Vga vga("vga");
    Intc intc("intc");
    Gpio gpio("gpio");
......



Hello Sir,

A viable workaround would be to use the following header files in the

.h file:

 

#include <cstdlib>

#include <cstring>

/* And so on ..*/

 

The modules may then be compiled happily with g++ (NOT gcc)

and executed.

Hope that helps.

Share this post


Link to post
Share on other sites

Tanks dakupoto but i would like to add another CPU, like:

NativeWrapper& cpu1 = *NativeWrapper::get_instance();
NativeWrapper& cpu2 = *NativeWrapper::get_instance();

Or

NativeWrapper cpu1("cpu1")
NativeWrapper cpu2("cpu2")

In second solution when I execute the simulation a message is displayed:
"terminate called Expired Effective throwing an instance of 'sc_core :: sc_report'
what (): error (E529) insert Module failed: simulation running
In file: ../../../../src/ csys/kernel/sc_module_registry.cpp: 69
In process: cpu1.compute @ 0 s "

Share this post


Link to post
Share on other sites

Tanks dakupoto but i would like to add another CPU, like:

NativeWrapper& cpu1 = *NativeWrapper::get_instance();
NativeWrapper& cpu2 = *NativeWrapper::get_instance();

Or

NativeWrapper cpu1("cpu1")
NativeWrapper cpu2("cpu2")

In second solution when I execute the simulation a message is displayed:

"terminate called Expired Effective throwing an instance of 'sc_core :: sc_report'

what (): error (E529) insert Module failed: simulation running

In file: ../../../../src/ csys/kernel/sc_module_registry.cpp: 69

In process: cpu1.compute @ 0 s "

Hello Sir,

The NativeWrapper constructor as you have provided reads as:

NativeWrapper::NativeWrapper(sc_core::sc_module_name name) : sc_module(name),

                                 irq("irq")

{

    SC_THREAD(compute);

    SC_METHOD(interrupt_handler_internal);

    sensitive << irq ;

    dont_initialize();

}

 

However, the constructor is invoked as:

NativeWrapper cpu1("cpu1")

 

Where is the interrupt request object ?

That is, has the IRQ object been created

BEFORE the NativeWrapper constructors

are invoked ?

Hope that helps.

Share this post


Link to post
Share on other sites

Hakim,

 

contrary to your topic line, the problem is not the way you call C from SystemC, but actually the other way round: How to come back to SystemC from a C implementation of an ISS to access the rest of the virtual platform again.  Note: I have not used this particular ISS and everything in my answer may just be the tip of the iceberg.

 

Did you see that comment:
 

    /*
       We use a singleton here. This is a limitation since it
       doesn't allow multiple NativeWrapper instances (multiple CPU
       in the platform), but it considerably reduces the
       complexity of Makefiles, hal.h, ...
    */

 

 

In all of the C callback functions, e.g. read_addr(), the NativeWrapper assumes that 'get_instance()' returns a pointer to the one and only NativeWrapper object in the system.

 

Instead of using this singleton function, add a new function to NativeWrapper to get the "current" CPU, based on the wrapping SystemC thread:

// add to NativeWrapper class
static NativeWrapper* get_current_instance();

// add to NativeWrapper.cpp
static NativeWrapper*
NativeWrapper::get_current_instance()
{
   sc_core::sc_object*  current_cpu_process = sc_core::sc_get_current_process_handle();
   sc_assert( current_cpu_process );

   NativeWrapper*  current_native_wrapper = dynamic_cast<NativeWrapper*>( current_cpu_process->get_parent_object() );
   sc_assert( current_native_wrapper );

   return current_native_wrapper;
}

And then replace the calls to 'get_instance()' in the C callback functions with this 'get_current_instance()' function.  You may still have problems with other parts of the ISS implementation and its assumptions on the current platform configuration.

 

 

Tanks dakupoto but i would like to add another CPU, like:

NativeWrapper& cpu1 = *NativeWrapper::get_instance();
NativeWrapper& cpu2 = *NativeWrapper::get_instance();

Or

NativeWrapper cpu1("cpu1")
NativeWrapper cpu2("cpu2")

In second solution when I execute the simulation a message is displayed:
"terminate called Expired Effective throwing an instance of 'sc_core :: sc_report'
what (): error (E529) insert Module failed: simulation running
In file: ../../../../src/ csys/kernel/sc_module_registry.cpp: 69
In process: cpu1.compute @ 0 s "

 

The first approach will always return the "one and only" NativeWrapper object.  Since you already managed to get access to the constructor (which has been private in your original example), you should not use it in your model.  Use the second approach with my sketched solution from above.  Otherwise, the first call to get_instance() from one of the callbacks will try to create a new CPU, even though the simulation is already running.

 

Side note: You should receive a proper error message instead of a call to std::terminate when using SystemC 2.3.0.

 

Greetings from Oldenburg,
  Philipp

 

Share this post


Link to post
Share on other sites

thank you very much dear friend Philipp, I did everything you said but an error message is displayed: native_wrapper.cpp:44: error: 'SC_ID_ASSERTION_FAILED_ ' was not declared in this scope.

the problem is in the line where we have:

                              

 sc_assert (current_cpu_process);

thanks for your help!

Share this post


Link to post
Share on other sites

native_wrapper.cpp:44: error: 'SC_ID_ASSERTION_FAILED_ ' was not declared in this scope.

 

This bug has been fixed in SystemC 2.3.0 among many others.  You should consider to migrate to the current version.

 

Alternatively, you can put the line

using sc_core::SC_ID_ASSERTION_FAILED_;

before the offending line.

 

/Philipp

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

×