Services and Modeling for Embedded Software Development
Embecosm divider strip
Prev  Next

4.2.6.  Upcalls

The Or1ksim ISS makes requests to read and write peripherals via the upcalls passed as arguments to or1ksim_init (see Section 4.1.1).

The Or1ksim ISS is implemented in C, which cannot easily call C++ class instance functions. The solution is to declare two static member functions which can be called from C. The call to or1ksim_init also received the address of the actual C++ class instance (cast to void *). This pointer is passed back with the upcall, so the static function can call the corresponding instance function.

A total of 4 functions are needed, one static and one instance each for read and write. The static functions use the native C/C++ types (unsigned long int), but convert to defined fixed width types for the instance functions. The native SystemC 64-bit unsigned type is used for the address (which is always 64 bits in TLM 2.0 function calls) and the POSIX 32-bit unsigned data type is used for the byte enable mask and data.

These upcall functions are not changed throughout this application note, so are declared private.

static int  staticReadUpcall (void              *instancePtr,
                              unsigned long int  addr,
                              unsigned char      mask[],
                              unsigned char      rdata[],
                              int                dataLen);

static int  staticWriteUpcall (void              *instancePtr,
                               unsigned long int  addr,
                               unsigned char      mask[],
                               unsigned char      wdata[],
                               int                dataLen);

int         readUpcall (unsigned long int  addr,
                        unsigned char      mask[],
                        unsigned char      rdata[],
                        int                dataLen);

int         writeUpcall (unsigned long int  addr,
                         unsigned char      mask[],
                         unsigned char      wdata[],
                         int                dataLen);
	  
[Caution]Caution

It might seem logical to use the SystemC limited precision types, rather than the POSIX types. However the SystemC types are not native C++ types, so will not cast as expected.

The transport mechanism is common to both, so provided in a utility function, doTrans. This function will be used and re-implemented in derived classes, so is declared protected and virtual.

When invoked, each upcall will need to populate a new payload. Since this is something local in both scope and extent to the upcall and its lifetime, the instinct is to declare it as an automatic variable within each upcall.

However the TLM 2.0 generic payload has a large underlying structure and complex initialization, so such a local declaration carries a significant performance penalty if it is constructed each time the upcall is used.

Since only one upcall is ever in use at any one time, we can declare the payload as a class instance variable. Since it is only used by the upcalls, it can be private to this class.

  tlm::tlm_generic_payload  trans;
	  
[Note]Note

The performance overhead in instantiating a generic payload is not mentioned in the TLM 2.0 LRM. I am indebted to Robert Günzel for bringing the issue to my attention.

Embecosm divider strip