CompileDES  3.12
Executable-Code Generation from Synchronised libFAUDES Automata
Execution Semantics

By synchronous automata we refer to executing shared events only if they are enabled in all component automata, and, when executed, then simultaneously in all component automata. These are the plain semantics commonly used in supervisory control theory. There is a relevant gap from this theory point of view to an actual implementation and we need to precisely formulate how CompileDES generated code fills this gap; relevant sources are CodePrimitives and AttributeCodeGeneratorEvent.

Which entity controls the occurrence of an event?

The occurrence of an event can be either controlled by the generated code or externally. Externally controlled events are referred to as "input-events".

With CompileDES, input-events are triggered by edges of digital signals. Choices are per event and per input line to trigger by positive edge or to trigger by negative edge or both. In order to detect signals with relevant initial value, an optional fake edge can be generated on program start; e.g., an input-event that is associated with a positive edge will be triggered at program start if the respective line evaluates true. For convenience purposes, events can also be triggered by a boolean expression given in terms of the target language, e.g., a function call with boolean return value.

At any instance of time, the generated code shall accept any input-event that has been detected. Here "accept" reads that once detected, transitions are executed and states are updated accordingly.

Events that are not input-events can be executed whenever enabled. Hence, the semantics so far need to be refined to achieve a deterministic behaviour.

If more than one event is enabled, which one shall occur?

CompileDES configurations attach an integer-priority attribute to each event. If multiple events are enabled, the one with the highest priority is considered to occur.

Merging priorities and the concept of input-events is done by the following two rules. At any instance of time,

  • if an input-event has been detected, the detected input-event with the highest priority shall be selected
  • if no event qualified for the first clause, and if a non-input event is enabled, then the enabled non-input with the highest priority shall be selected

Once an event is selected, transitions are executed and states are updated. It is considered an error if an input-event is detected which is not enabled by all component automata. Historically, libFAUDES uses negative priorities for input-events. This is somewhat counter-intuitive. For CompileDES configurations, all priorities are configured positive (with strategic conversion for the internal representation).

How to handle simultaneous events?

From the theory point of view, an arbitrary number of events can occur within an arbitrary short duration of physical time, however, events can not occur simultaneously; ie. the state-tracjectory is assumed to be a piecewise continuous function and logic time is related to physical time at an arbitrarily high resolution. In contrast, an implementation based on scan-cycles provides only a limited resolution of physical time. Successive events within one scan cycle are sensed simultaneously. For a faithful recovery of logic time, simultaneously sensed events must be ordered optimistically. This leads to the following relaxed scheme of event selection.

Initialise the set of pending events to be empty. Then go through the following steps once per scan cycle

  • figure the set of events enabled by all component automata
  • if input events are detected insert them to the set of pending events
  • if a pending event is enabled, select the one with the highest priority
  • if no event is selected so far, and if an event is enabled, select the one with the highest priority
  • if an event has been selected, execute transitions and update the state accordingly
  • if no event has been selected, there is nothing to do until a new input event is detected

It is considered an error if there are pending input-events but neither input-events nor non-input-events are enabled. This error should be reported to the host program and the pending event should be discarded. The current implementation of CompileDES sets a status flag correspondingly.

If there are pending input-events that can not be executed this is not considered an error as long as some other event can be executed. In this case one can optionally loop the above steps within one scan cycle until there are no more pending events. However, this approach is only suitable if the composed discrete-event-system has no non-input-event strongly connected components. As a safe variation of this approach CompileDes can optionally loop until there are no more pending input events enabled. In general, it is not recommended to sacrifice execution semantics for performance. On a decent hardware/compiler, CompileDES will achieve sufficiently fast cycle times without a nested event-execution loop.

Other special cases: timer-events and output-events

Timers are used to relate logic time with physical time. CompileDES supports timers with a fixed initial value and the common start/stop/reset semantics, the latter triggered by individually specified events. The elapse of a timer in turn triggers the respective timer-event. Although timers are implemented by generated code, regarding event execution they are considered as input-events.

Output-events are events with actions attached. Supported actions include setting or clearing line levels as well as evaluating target language expressions, e.g. setting flags or calling functions. Regarding execution semantics as outlined above, output-events are treated the same as other non-input events.