Posting Events

A common task for memory mapped devices is that they need to simulate delays, TEMU is a discrete event simulation framework, and we can post events on the event queue provided by a CPU model. There are two types of "normal" events that can be posted, firstly stacked events, which are executed at the end of the instruction that triggered the event posting, and secondly timed events (with a delay in cycles, nanoseconds or seconds). Note that all events are rounded to a number of cycles and no event will be triggered in the middle of an instruction.

There are two items to take care of for event posting, firstly an event must be registered in order to provide snapshot capabilities, and secondly an event must be posted. The registration is done in the model’s constructor, and is very easy, first define an event function with type void (evfunc)(temu_Event), then add an int64_t event id to your model and then call the following in the constructor:

model->eventId = temu_eventPublish("mymodel.event",
model, evfunc);

The event publication ensures that the event queues can be restored later on (after serialisation) without having to do anything else on your side.

There is one additional thing that needs to be done, your model needs to know where any event will be posted, and this is done by attaching a time source to your model. A time source property is already available in the temu_Object field, so the only thing needed is to connect to it in the command line:

temu> connect-timesource obj=foo ts=cpu0

In TEMU, time is provided by processor models. That means that there are multiple time-source if there are multiple processors in the system. A processor and the devices that uses the processor as a time source form a clock domain. This means that two events triggered by different processors may not be strictly ordered in apparent time, however they will be well ordered with other events triggered by the same processor.

The next step is to ensure that an event is actually posted by your model.

You should not enqueue an event that is already enqueued, if you do this, a warning will be emitted, and the already enqueued event will be dequeued before enqueuing the event again.

Go ahead, you can easily stack post an event in your model, by adding the following in your read and write accessors:

temu_eventPostStack(model->super.TimeSource,
                    model->eventId, teSE_Cpu);

The last parameter is a synchronisation parameter, that are useful for multi-processor systems. In multi-processor systems, events can be posted so all processors will have the same time (plus a few cycles depending on the cycle cost time of the last instruction in each processor). To post a synchronised event, change it to teSE_Machine. However, for stacked events, machine posted events are events that are executed at the start of the next quanta. To run the processor until it hits error mode, just run the following command:

temu> step obj=cpu0 steps=2
0.000000: info: foo : updating a from 0 to 42
0.000002: info: foo : event triggered
0.000002: info: foo : reading a as 42
0.000004: info: foo : event triggered

As you notice, the first event is executed at time 0.000002 and not at time 0.000000, this is because events are triggered after an instruction has been executed, and that means that the CPU time is updated before the checking of the event queue.