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 | |
---|---|
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 | |
---|---|
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. |