dataType

Data Type

This is possibly the most controversial topic in the field of TLM.

Here we are ONLY focusing on the definition of the "standard" Data attribute. If a user wishes to use a data type that does not fit within this definition, they are free to do so, using a user defined type. This is absolutely imperative if the Master and Slave need to know (and agree upon) a complex data structure.

So, the Generic Data type need only concern itself with "untyped" data.

The AIM is to facilitate the transmission of data resting in one model to another.

At some point, one single data copy from the source to the destination is normally required (see below for how even this data copy may be avoided). Other copies may be recommended for safety reasons.

The Interoperability layer is about speed. Hence the most speed-advantageous approach should be adopted.

In general, busses allow various amounts of data to be transmitted in one "transaction", to reduce the setup costs in the bus of each transaction. Since the interoperability later also needs to focus on speed, it too needs to allow for various sizes.

We have seen the life of a transaction is well defined. One "safe" approach would be to demand that the data be part of that transaction. In this approach the source would copy it's data to the data part of the transaction, and the destination model would copy the data part of the transaction to its final (internal to the model) destination.

This incurs one extra data copy. This increases safety at the expense of speed.

To remove this extra copy, the master must provide a "pointer" to either it's source data (for a write transaction) or the eventual destination address (for a read transaction).

This can be done at the interoperability later, while allowing the convenience layer, as it should, to better ensure safety.

Safety

A convenience layer can provide ports which own the data, just as the transaction is owned, and in doing so provide a safer solution. The storage for the control aspects of the transaction would then be kept alongside the storage for the data aspects, and they would be treated together. In this case, the solution can look to the user as if they were passing by value.

Faster still avoiding the copy

To remove the last copy required the use of "Copy on Write" vectors. Here a "smart pointer" is used to store data in both the source and destination. The smart pointer allows for a slice of data to be present in both vectors. Then, if one vector is written to, a copy is made in the other vector. Because a copy is only done IF the data is written to, then the copy on write vector is much more efficient. However, this comes with the cost of

  1. transmitting and storing the information about the slice that needs to be replicated in both vectors.
  2. :2. checking each write to the vectors to make sure the write does not go over a slice.

Therefore, for small data chunks this approach is relatively costly. But for large arrays of data then it can be extremely effective. It is typically deployed in disk caches.

Today we have little evidence about the average sizes of master and slave memories, the data transfer between them, or the frequency of writes to them. However, most models do not make use of CoW vectors. Hence the standard data type is left as "normal" data, while the CoW vector is offered as an alternative in the attribute pallet.

Type of "standard" Data Type

Because the Master and Slave have to share this data type to remove the copy, then it needs to be the most commonly used memory data type. We have chosen unsigned char [].

Each IP block has to know how to serialise (or de-serialise) it's data to (or from) an unsigned char [].

This means that potentially a System Initiator could treat the data as a "complex structure", while a "dumb memory" System Target can simply treat everything as bytes.

If the master does not store it's memory using unsigned char [] then it will require (in the port, provided by the convenience layer) sufficient memory to store the source or destination data. However, this memory MUST be unsigned char [].

It is then the job of the master and slave to "serialise" it's own data into unsigned char [].

Use of Templates

The approach many people have taken has been to use a template class. However this approach has a number of flaws. Not least of which, it does not provide a standard data type. This means that bridges and routers, as well as master and slaves will all potentially need to do data manipulation. This means that all initiator-target pairs effectively become (more expensive) master slaves pairs.

Of course a user is free to define their own types (as mentioned above), and for known complex data structures this may be required. The standard data type provides a known "base line" to which all data can be converted.

Endian-ness

Note that some models will chose to represent their internal data "endianed" to match the final hardware solution. The standard data type uses bytes, the least significant byte being at index 0. The way model data is serialised onto the data type is left to the model.

This data type has to be fixed, as otherwise the master and slave do not know what to convert to.