2.4.2.  Execution Logic

In this section, the flow of execution during the simulation session will be discussed. The actions of the base class will be clarified as well as the correlation of model action and model updates.

2.4.2.1 Event Queue

We presume that the elaboration session and the reset process have already been finished, and simulation is about to begin. Even before the application triggers, the evaluation of the first cycles there may be pending events in Octopus’ event queue, scheduled in the initialization stage of a model. A model can schedule events only for itself, it avails the motNextEval function with the cycle offset and a TaskTypeT value as parameters. In earlier versions of Octopus there were – additionally to the normal event-driven models – so-called active models, which were evaluated automatically every clock cycle. The concept was used for CPU models, changing their state in each cycle. The active models were discontinued because the administrative and performance expense is basically the same as for self-scheduling models. Especially for CPU models there are many instructions that take more than one clock cycle, e. g. due to memory speed. So it would be a waste of performance to evaluate the model in the meantime. Without active models there is only one type of model execution logic, making the structure and maintenance of Octopus easier.

So if the event queue is empty, Octopus advances the simulation time and returns control to the application. In the other case, the time is set to the point of the first event in the queue and the according models are evaluated, invoking the Eval callback of each model with a pending event. The model now determines the action, it has to perform, by interpreting the bits in the 31-bit TaskTypeT value. This is actually a 4-byte long integer with the MSB being used by Octopus internally. Depending on the action to be performed, the model could now initiate an update of a memory mapped module register by using the base class function motSetReg16 for 2-byte registers. The base class modifies that value in an internal data structure. The next bus read access to the address of the register will receive the new register content.

2.4.2.2 Port Update

The callback could update an output port using the motPutPort function of Octopus, or – better – the base class encapsulation SetPin. The latter has the advantage, that only the port index instead of the port handle and time offset has to be passed beside the type-token combination. In the configuration file, a signal is attached to each of the ports by name, Octopus now searches the netlist for this signal name to ascertain to which ports the signal is assigned to on the input side. Now it is known to which port the update has to be delivered to. The offset, specified for the output port, reflects the number of cycles, the port delays its output. After this time Octopus informs the other model, using the Update callback. As usual, the update information is parsed by the base class, which then knows exactly what port has been updated. It raises the handler callback function that has been registered in the base class for receiving updates on that specific port. If the application, respectively the user, had decided to monitor the signal, the update is passed to the signal dumper, too. The signal dumper is the piece of code, that produces signal dump files, e. g. in VCD format, for all signals selected for monitoring. The update handler function for the port addressed receives the type-token pair of information and can easily react on the signal change, possibly with scheduling an event using motNextEval.

2.4.2.3 Bus Access

Unlike normal signals, which are usually connected to two ports only, a bus signal passes several models, but addresses only a particular one. A “bus communication consists of two successive communication events” ([KLR99, section 3.4.5]):

The bus master,
usually the processor, requests for a read or write access to a memory-mapped register of some component. The generated request keeps all necessary data, like the address of the accessed register, the data, if it is a write access, and bus control information. Octopus parses the bus token generated by the master, and sends it to the Access callback of the appropriate models, depending on the entries of the memory map. The base class takes the token and passes the extracted information to the read or write handler function assigned to the specific register.
The addressed component
responds, either acknowledging the access or signaling an sending an error. Along with the acknowledgment comes the data if it has been a read access. In the implementation, a handler function for write accesses to a particular register could be registered. Within this handler function, the change of state of the module takes place. The base class generates acknowledge and returns it to Octopus.

2.4.2.4 Debug Functionality

Generally, there are two versions of Octopus used for simulation. In the model development process, the debug version allows sophisticated debugging, while for model delivery, when the performance is most important, the fast version without any debug code is linked.

The difference between debug and fast version lies not only in the different library files of Octopus, but also in the header files. All debug commands are C macros, like the command for printing debug information:

 
motMODELDEBUG1PARAM(level , string ,param1)

Of course, when using macros it is not possible to pass a variable number of parameters like one would do with a printf statement. So there are macros for zero to nine parameters. The level parameter specifies the debug level. There are nine levels available for each model, so for execution it is feasible to run different models in different debug levels to gain the level of detail of information needed. If the developer wants to use a whole code block as debug code, he can embed it in model debug brackets:

 
motMODELDEBUG_START( l e v e l ) 
 
. . .  code  . . . 
 
motMODELDEBUG_END

When compiling and linking for debug, the brackets are substituted with the debug level check code, when compiling for delivery it is replaced with an #ifdef 0 ... endif

Model manager commands are supported in Octopus by allowing models to register their own commands. With this technique, models can e. g. implement debug commands to show internal states, or also manipulate them. All commands have the following syntax:

 
<access to octopus commands> <model instance> <command> <options>

In later subsections of chapter  3.1 on page 169, examples for debug commands will be presented.