The SR Domain

Introduction

The Synchronous/Reactive domain implements a model of computation based on a the synchronous model of time like that in the Esterel language [1]. It is well-suited for specifying discrete reactive controllers--systems that maintain an ongoing dialog with their environment and must react to it at a speed dictated by the environment.

The model of time in the SR domain is based on the concept of an infinitely-fast machine. When an input arrives from the outside world, the infinitely fast machine computes and produces its reaction at the same instant the input arrives. Time is thus a series of discrete instants when the machine is performing a computation. Between these instants, nothing happens.

The stars in the SR domain communicate through unbuffered single driver, multiple receiver arcs. These arcs carry valued events, which may be present with a value, absent, or unknown in each instant. The value on an arc does not persist between instants.

The SR domain domain simulates the execution of an infinitely-fast machine an instant at a time. The behavior of the system in each instant is simulated in two phases. In the first phase, the stars in the system are fired repeatedly (their go() methods are called) to reach a fixed-point on the arcs' values. The stars in the SR domain satisfy a monotonicity constraint that ensures this fixed point always exists and is unique, regardless of firing order. In the second phase, all stars are instructed (their tick() method is called) to advance their state, if any, based on the values of their input arcs. This prepares them for the next instant.

Broadly, there are two types of stars in the SR domain: strict and non-strict. If any input to a strict star is unknown, then all of its outputs are unknown. A two-input adder, for example, behaves like this--it cannot say anything about its output until the values of both inputs are known. A non-strict star, by contrast, can produce some outputs before all of its inputs are known. A two-input multiplexer is an example: when the selection input is known, it can ignore the unselected input.

Non-strict stars are the key to avoiding deadlocked situations when there are cyclic connections in the system. If all the stars in a cycle are strict, they each need all of their inputs before producing an output--all will be left waiting. The deadlock can be broken by introducing a non-strict star into the cycle that can produce an output without having all inputs from other stars in the cycle


Writing SR Stars

A porthole on an SR star can have an unknown value, an absent value, or be present with a particle. These states can be tested with the following methods, which can be called on both input and output PortHoles:

int SRPortHole::known()
Return TRUE when the value in the port is is known
int SRPortHole::present()
Return TRUE when the value in the port is present
int SRPortHole::absent()
Return TRUE when the value in the port is absent
Once the presence of a particle on an input port is established, it can be accessed as follows:

Particle & InSRPort::get()
Return the particle in the port. This should only be called when present() returns TRUE
The value on an output port can be established by calling one of the following. In an instant, a star may invoke one of these methods exactly once--more than this is an error. (This ensures the fixed-point computation in an instant always terminates.)

Particle & OutSRPort::emit()
Force the value on the output port to be present and return a reference to the output particle.
void OutSRPort::makeAbsent()
Force the value on the output port to be absent.
A number of methods set attributes of SR stars. These should be called in the setup method of a star as appropriate. By default, none of these attributes is assumed to hold.

SRStar::reactive()
Indicate the star is reactive--it needs at least one present input to produce a present output.
Star::noInternalState()
Indicate the star has no internal state--its behavior in an instant is a function only of the inputs in that instant, and not on history.
By default, a star in the SR domain is strict. Here is (abbreviated) ptlang source for a two-input adder: defstar { name { Add } domain { SR } input { name { input1 } type { int } } input { name { input2 } type { int } } output { name { output } type { int } } setup { reactive(); noInternalState(); } go { if ( input1.present() && input2.present() ) { output.emit() << int(input1.get()) + int(input2.get()); } else { Error::abortRun(*this, "One input present, the other absent"); } } } Non-strict stars inherit from the SRNonStrictStar class. Here is abbreviated source for a non-strict two-input multiplexer: defstar { name { Mux } domain { SR } derivedFrom { SRNonStrictStar } input { name { trueInput } type { int } } input { name { falseInput } type { int } } input { name { select } type { int } } output { name { output } type { int } } setup { noInternalState(); reactive(); } go { if ( !output.known() && select.known() ) { if ( select.present() ) { if ( int(select.get()) ) { // Select is true--copy the true input if it's known if ( trueInput.known() ) { if ( trueInput.present() ) { output.emit() << int(trueInput.get()); } else { // true input is absent: make the output absent output.makeAbsent(); } } } else { // Select is false--copy the false input if it's known if ( falseInput.known() ) { if ( falseInput.present() ) { output.emit() << int(trueInput.get()); } else { // false input is absent: make the output absent output.makeAbsent(); } } } } else { // Select is absent: make the output absent output.makeAbsent(); } } } }
[1]
Gerard Berry and Georges Gonthier.
The Esterel synchronous programming language: Design, semantics, implementation.
Science of Computer Programming, 19(2):87-152, November 1992.
ftp://cma.cma.fr/esterel/BerryGonthierSCP.ps.Z .