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

4.3.4.  Upcalls

Two functions are declared as static member functions to implement the upcalls from the Or1ksim library (see Section 4.2.6 for an explanation of why these functions are static).

The static functions receive the pointer to the Or1ksimSC instance which originally started the Or1ksim ISS (provided as an argument to or1ksim_init described in Section 4.3.3).

This allows each static function to call the instance function which implements the upcall, as shown here with staticReadUpcall:

int
Or1ksimSC::staticReadUpcall (void              *instancePtr,
                             unsigned long int  addr,
                             unsigned char      mask[],
                             unsigned char      rdata[],
                             int                dataLen)
{
  Or1ksimSC *classPtr = (Or1ksimSC *) instancePtr;
  return  classPtr->readUpcall (addr, mask, rdata, dataLen);

}       // staticReadUpcall()
	

The instancePtr argument allows identification of the particular instance of the class which called or1ksim_run and hence to which the upcall is directed. The remaining arguments are passed to the instance method unchanged.

[Caution]Caution

It might be thought that providing a direct upcall to the C++ upcall functions of the class would be more efficient, using the C++ member reference operator (::*). However the linkage to a member is much more complex (to cope with inheritance and overloading). Lack of standardization in the C++ Application Binary Interface (ABI) means that such linkage between C and C++ will not necessarily work.

Linkage to static functions is much simpler and usually works between C and C++. So the approach used here is more reliable.

The upcalls from the ISS generate the transactional activity. These functions set up the payload, execute the transaction (i.e exchange the payload and result with the target) and return the result to the ISS.

The example here is coded in a very simple fashion, in the knowledge that the requests to read are always four bytes long (the OpenRISC 1000 has a simple 32 bit bus), possibly with some bytes masked out for byte and half-word reads. This matches the default BUSWIDTH of the simple initiator socket.

As noted in Section 4.2.6, the payload is declared as a class instance variable, rather than locally here for performance reasons. This has the added benefit that it will also work should we ever convert the model to using a non-blocking socket, where the lifetime of the payload would need to be longer than the lifetime of the upcall. TLM 2.0 requires that the payload, data and mask fields all remain valid for the duration of the complete transaction.

Embecosm divider strip