This coding style works with 2 timing points in each transaction, one in the function call and the other in the return for the b_transport function (using the base protocol these points corresponds to the start of the petition and the start of the response). We can put these two points in the same time to mark that the transaction is not using time.
Time passed as parameter to the b_transport function marks start time of the transaction from the actual simulation time. In normal use, that time will be always 0 (unless we are using temporal decoupling). The target can use wait() inside the b_transport function to spend simulation time or can return
immediately and modify the time parameter to mark what time he spent. Later, the Initiator may call wait() for that time to increase simulation time.
That system allows the use of temporal decoupling. This mechanism allows parts of our design to run ahead the global simulation time until it needs to communicate with others system models, when it synchronizes again with the global simulation time.
When a temporal decoupled module in advanced time needs to communicate with other module we have two options:
- Assume a value for that communication
- Synchronize with whole system: wait for global simulation time arrives to its simulation time.
In this technique we use b_transport, filling the time parameter in the function call. In this parameter we annotate the time that our modules are ahead the simulation time, so the Target returns in the time parameter the offset time about simulation time. This means that adding that parameter time to actual simulation time give us the advanced simulation time for that Target.
And why is that for? Because with this technique we boost simulation speed, because SystemC simulator had less context switching and less overhead of guessing what module is next to simulate.
If we allow one module to run ahead with no limit, others parts of the simulation would never be simulated. To avoid that, TLM-2.0 introduces global quantum, that’s the maximum time that a module can be ahead global simulation time. That quantum can be modified in the simulation, and is a trade off between simulation speed and simulation accuracy. If this quantum is small, our simulation will have lot of synchronization (and lost of performance), but if we chose a big value for this quantum, simulation can be wrong.
The typical example of using temporal decoupling is the simulation of a system with a CPU, memory, one timer and some slow peripheral (a UART). Software running on the simulated CPU basically fetches instructions from memory and executes them in the CPU, and only interact with the rest of the system when timer triggers and interrupt (i.e. every 1 millisecond). In this case, the CPU module can run ahead global simulation until 1 millisecond, accessing directly to memory (using DMI). In this way, it’s possible to have a very detailed model of the timer without slowing simulation performance.
This mechanism can be started and stopped dynamically in the simulation. Can be useful to have a first part of the simulation very fast and unaccurate, and then disable temporal decoupling to have better accuracy losing some simulation performance.