Content uploaded by Ben Horowitz
Author content
All content in this area was uploaded by Ben Horowitz on Feb 13, 2014
Content may be subject to copyright.
Content uploaded by Ben Horowitz
Author content
All content in this area was uploaded by Ben Horowitz on Jan 03, 2014
Content may be subject to copyright.
1
Giotto:
A Time-triggered Language for
Embedded Programming
Thomas A. Henzinger Benjamin Horowitz Christoph M. Kirsch
Electrical Engineering and Computer Sciences
University of California, Berkeley
Abstract—Giotto provides an abstract programmer’s model
for the implementation of embedded control systems with hard
real-time constraints. A typical control application consists of
periodic software tasks together with a mode-switching logic
for enabling and disabling tasks. Giotto specifies time-triggered
sensor readings, task invocations, actuator updates, and mode
switches independent of any implementation platform. Giotto
can be annotated with platform constraints such as task-to-
host mappings, and task and communication schedules. The
annotations are directives for the Giotto compiler, but they do
not alter the functionality and timing of a Giotto program.
By separating the platform-independent from the platform-
dependent concerns, Giotto enables a great deal of flexibility in
choosing control platforms as well as a great deal of automation
in the validation and synthesis of control software. The time-
triggered nature of Giotto achieves timing predictability, which
makes Giotto particularly suitable for safety-critical applications.
Keywords—Programming languages, real-time systems, con-
trol systems, embedded software.
I. INTRODUCTION
Giotto provides a programming abstraction for hard real-
time applications that exhibit time-periodic and multimodal
behavior, as in automotive, aerospace, and manufacturing
control.
Traditional control design happens at a mathematical level
of abstraction, with the control engineer manipulating differ-
ential equations and mode-switching logic using tools such as
Matlab or MatrixX. Typical activities of the control engineer
include modeling of the plant behavior and disturbances, deriv-
ing and optimizing control laws, and validating functionality
and performance of the model through analysis and simulation.
If the validated design is to be implemented in software, it
is then handed off to a software engineer who writes code
for a particular platform (we use the word “platform” to
stand for a hardware configuration together with a real-time
operating system). Typical activities of the software engineer
include decomposing the necessary computational activities
into periodic tasks, assigning tasks to CPUs and setting task
priorities to meet the desired hard real-time constraints under
the given scheduling mechanism and hardware performance,
This research was supported in part by the AFOSR MURI grant F49620-
00-1-0327, the DARPA SEC grant F33615-C-98-3614, the MARCO GSRC
grant 98-DT-660, and the NSF grant CCR-0208875.
A preliminary version of this paper appeared in the Proceedings of the
International Workshop on Embedded Software, vol. 2211 of Lecture Notes
in Computer Science. Springer-Verlag, 2001, pp. 166–184.
and achieving the desired degree of fault tolerance through
replication and error correction. While limited automation for
these activities is available in the form of code-generation
tools, the software engineer has final authority over putting
the implementation together through an often iterative process
of code integration, testing, and optimization.
Giotto provides an intermediate level of abstraction, which
(i) permits the software engineer to communicate more ef-
fectively with the control engineer, and (ii) keeps the im-
plementation and its properties more closely aligned with
the mathematical model of the control design. Specifically,
Giotto defines a software architecture of the implementation
which specifies its functionality and timing. Functionality and
timing are sufficient and necessary for ensuring that the imple-
mentation is consistent with the mathematical model. On the
other hand, Giotto abstracts away from the realization of the
software architecture on a specific platform, and frees the soft-
ware engineer from worrying about issues such as hardware
performance and scheduling mechanism while communicating
with the control engineer. After writing a Giotto program, the
second task of the software engineer remains of course to
implement the program on the given platform. In Giotto, this
second task, which requires no interaction with the control
engineer, is effectively decoupled from the first, and can in
large parts be automated by increasingly powerful compilers.
Giotto compilation guarantees the preservation of functionality
and timing, and thus removes the need for a tedious and error-
prone iteration of code evaluation and optimization.
The Giotto design flow is shown in Figure 1. The separation
of logical correctness concerns (functionality and timing) from
physical realization concerns (mapping and scheduling) has
the added benefit that a Giotto program is entirely platform
independent and can be compiled on different, even heteroge-
neous, platforms.
Motivating example. Giotto is designed specifically for em-
bedded control applications. Consider a typical fly-by-wire
flight control system [1], [2], which consists of three types of
interconnected components (see Figure 2): sensors, CPUs for
computing control laws, and actuators. The sensors include
an inertial measurement unit (IMU), for measuring linear
acceleration and angular velocity; a global positioning sys-
tem (GPS), for measuring position; an air data measurement
system, for measuring such quantities as air pressure; and
2
Fig. 2. A fly-by-wire flight control system.
Fig. 1. Giotto-based control-systems development.
the pilot’s controls, such as the pilot’s stick. Each sensor has
its own timing properties: the IMU, for example, outputs its
measurement 1,000 times per second, whereas the pilot’s stick
outputs its measurement only 500 times per second. Three
separate control laws —for pitch, lateral, and throttle control—
need to be computed. The system has four actuators: two for
the ailerons, one for the tailplane, and one for the rudder. The
timing requirements on the control laws and actuator tasks
are also shown in Figure 2. The reader may wonder why the
actuator tasks need to run more frequently than the control
laws. The reason is that the actuator tasks are responsible for
the stabilization of quickly moving mechanical hardware, and
thus need to be an order of magnitude more responsive than
the control laws.
We have just described one operational mode of the fly-
by-wire flight control system, namely the cruise mode. There
are four additional modes: the take-off, landing, autopilot, and
degraded modes. In each of these modes, additional sensing
tasks, control laws, and actuating tasks need to be executed,
as well as some of the cruise tasks removed. For example,
in the take-off mode, the landing gear must be retracted. In
the autopilot mode, the control system takes inputs from a
supervisory flight planner, instead of from the pilot’s stick.
In the degraded mode, some of the sensors or actuators
have suffered damage; the control system compensates by not
allowing maneuvers which are as aggressive as those permitted
in the cruise mode.
The Giotto abstraction. Giotto provides a programmer’s
abstraction for specifying control systems that are structured
like the previous fly-by-wire example. The basic functional
unit in Giotto is the task, which is a periodically executed
piece of, say, C code. Several concurrent tasks make up a
mode. Tasks can be added or removed by switching from one
mode to another. Tasks communicate with each other, as well
as with sensors and actuators, by so-called drivers, which is
code that transports and converts values between ports. While
a task represents application-level computation that consumes
a non-negligible amount of CPU time, a driver is bounded code
that can be executed essentially instantaneously on the system
level, with environment interrupts disabled (more precisely,
drivers satisfy the synchrony assumption [3], that they can be
executed before the environment state changes
1
). In this way,
the Giotto abstraction integrates scheduled computation (tasks)
and synchronous communication (drivers). The periodic invo-
cation of tasks, the reading of sensor values, the writing of
actuator values, and the mode switching are all triggered by
real time. For example, one task
may be invoked every 2 ms
and read a sensor value upon each invocation;
2
another task
may be invoked every 3 ms and write an actuator value upon
each completion; and a mode switch may be contemplated
every 6 ms. This time-triggered semantics enables efficient
reasoning about the timing behavior of a Giotto program, in
particular, whether it conforms to the timing requirements of
a mathematical (e.g., Matlab) model of the control design.
A Giotto program does not specify where, how, and when
1
Since drivers cannot depend on each other, no issues of fixed-point
semantics arise.
2
While any choice of time unit is possible, we use milliseconds throughout
the paper.
3
tasks are scheduled. The Giotto program with tasks and
can be compiled on platforms that have a single CPU
(by time sharing the two tasks) as well as on platforms with
two CPUs (by parallelism); it can be compiled on platforms
with preemptive priority scheduling (such as most real-time
operating systems) as well as on truly time-triggered platforms
(such as the time-triggered architecture [4]). All the Giotto
compiler needs to ensure is that the semantics of the program
—i.e., functionality and timing— is preserved. To this end,
the compiler needs to solve a possibly distributed scheduling
problem. This can be difficult, and to make the job of the
compiler easier, a Giotto program can be annotated with
compiler directives in the form of platform constraints. A
platform constraint may map a particular task to a particular
CPU, assign a particular priority to a particular task, or
schedule a particular communication event between tasks in
a particular time slot. Such annotations, however, in no way
modify the functionality and timing of a Giotto program;
they simply aid the compiler in realizing the semantics of the
program.
Outline of the paper. We first give an informal introduction
to Giotto in Section II, followed by a formal definition of the
language in Section III. In Section IV, we define an abstract
version of the scheduling problem that needs to be solved by
the Giotto compiler, and we illustrate how a program can be
annotated to guide distributed code generation. In Section V,
we give pointers to current Giotto implementations and relate
Giotto to the literature.
II. INFORMAL DESCRIPTION OF GIOTTO
Ports. In Giotto all data is communicated through ports. A
port represents a typed variable with a unique location in a
globally shared name space. We use the global name space for
ports as a virtual concept to simplify the definition of Giotto.
An implementation of Giotto is not required to be a shared-
memory system. Every port is persistent in the sense that the
port keeps its value over time, until it is updated. There are
mutually disjoint sets of sensor ports, actuator ports, and task
ports in a Giotto program. The sensor ports are updated by
the environment; all other ports are updated by the Giotto
program. The task ports are used to communicate data between
concurrent tasks. Task ports can also be used to transfer data
from one mode to the next: task ports can be designated as
mode ports of a given mode, and assigned a value every time
the mode is entered.
Tasks. A typical Giotto task
is shown in Figure 3. The
task has a set of two input ports and a set of
two output ports, all of which are depicted by bullets. The
input ports of are distinct from all other ports in the Giotto
program. The output ports of may be shared with other
tasks as long as the tasks are not invoked in the same mode.
In general, a task may have an arbitrary number of input
and output ports. A task may also maintain a state, which
can be viewed as a set of private ports whose values are
inaccessible outside the task. The state of is denoted by
. Finally, the task has a function from its input ports and
its current state to its output ports and its next state. The task
Fig. 3. A task .
Fig. 4. An invocation of task .
function is implemented by a sequential program, and can be
written in an arbitrary programming language. It is important
to note that the execution of has no internal synchronization
points and cannot be terminated prematurely; in Giotto all
synchronization is specified explicitly outside of tasks. For a
given platform, the Giotto compiler will need to know the
worst-case execution time of on each available CPU.
Task invocations. Giotto tasks are periodic tasks: they are
invoked at regularly spaced points in time. An invocation of
a task is shown in Figure 4. The task invocation has a
frequency given by a non-zero natural number; the real-
time frequency will be determined later by dividing the real-
time period of the current mode by . The task invocation
specifies a driver which provides values for the input ports .
The first input port is loaded with the value of some other
port , and the second input port is loaded with the constant
value . In general, a driver is a function that converts the
values of sensor ports and mode ports of the current mode
to values for the input ports, or loads the input ports with
constants. Drivers can be guarded: the guard of a driver is
a predicate on sensor and mode ports. The invoked task is
executed only if the driver guard evaluates to true; otherwise,
the task execution is skipped.
The time line for an invocation of the task
is shown in
Figure 5. The invocation starts at some time with a
communication phase in which the driver guard is evaluated
and the input-port values are loaded. The Giotto semantics
prescribes that the communication phase —i.e., the execution
of the driver — is performed in logically zero time. In other
words, a Giotto driver is an atomic unit of computation that
cannot be interrupted. The synchronous communication phase
is followed by a scheduled computation phase. The Giotto
semantics prescribes that at time the state and output
ports of are updated to the (deterministic) result of applied
to the state and input ports of at time . The length
of the interval between and is determined by the
frequency . We say that the task is logically running
from time to time . The Giotto logical abstraction
does not specify when, where, and how the actual computa-
tion of is physically performed between and .
However, the time at which the task output ports are updated
is determined, and therefore, for any given real-time trace of
4
Fig. 5. The time line for an invocation of task .
sensor values, all values that are communicated between tasks
and to the actuator ports are determined [5]. Instantaneous
communication and time-deterministic computation are the
two essential ingredients of the Giotto logical abstraction. A
compiler must be faithful to this abstraction; for example, task
inputs may be loaded after time , and the execution of
may be preempted by other tasks, as long as at time
the values of the task output ports are those specified by the
Giotto semantics.
Modes. A Giotto program consists of a set of modes, each
of which repeats the invocation of a fixed set of tasks. The
Giotto program is in one mode at a time. Possible transitions
from a mode to other modes are specified by mode switches.
A mode switch can remove some tasks, and add others.
Formally, a mode consists of a period, a set of mode ports,
a set of task invocations, a set of actuator updates, and a set
of mode switches. Figure 6 shows a mode which contains
invocations of two tasks, and . The period of is
10 ms; that is, while the program is in mode , its execution
repeats the same pattern of task invocations every 10 ms. The
task has two input ports, and , two output ports,
and , a state , and a function . The task is defined
in a similar way. Moreover, there is one sensor port, , one
actuator port, , and a mode port, , which is not updated by
any task in mode . The value of stays constant while the
program is in mode ; it can be used to transfer a value from
a previous mode to mode . In addition to , all output ports
of tasks invoked in the mode — , , , and — are, by
default, also mode ports; they must be initialized upon entering
mode . The mode ports are visible outside the scope of ,
as indicated by the dashed lines. A mode switch may copy the
values at these ports to mode ports of a successor mode. The
invocation of task in mode has the frequency ,
which means that is invoked once every 10 ms while the
program is in mode . The invocation of in mode has the
driver , which copies the value of the mode port into
and the value of the output port of into . The invocation
of task has the frequency , which means that is
invoked once every 5 ms as long as the program is in mode .
The invocation of has the driver , which connects the
output port of to , the sensor port to , and the output
port of to . The mode has one actuator update, which
is a driver that copies the value of the output port of
to the actuator port with the actuator frequency ;
that is, once every 10 ms.
Fig. 6. A mode .
Figure 7 shows the exact timing of a single round of
mode , which takes 10 ms. As long as the program is in
mode , one such round follows another. The round begins
at the time instant with an instantaneous communication
phase for the invocations of tasks and , during which
the two drivers and are executed. The Giotto semantics
does not specify how the computations of the task functions
and are physically scheduled; they could be scheduled
in any order on a single CPU, or in parallel on two CPUs.
The Giotto semantics specifies only that after 5 ms, at time
instant , the results of the scheduled computation of are
made available at the output ports of
. The second invocation
of begins with another execution of driver , still at time ,
which samples the most recent value from the sensor port .
However, the two invocations of start with the same value
at input port , because the value stored in is not updated
until time instant ms, no matter whether or not
finishes its actual computation before . According to the
Giotto semantics, the output values of the invocation of must
not be available before . Any implementation that schedules
the invocation of
before the first invocation of must
therefore keep available two sets of values for the output ports
of . The round is finished after writing the output values of
the invocation of and of the second invocation of to their
output ports at time , and after updating the actuator port
at the same time. The beginning of the next round shows that
the input port is loaded with the new value produced by .
Mode switches. In order to give an example of mode switch-
ing we introduce a second mode , shown in Figure 8. The
main difference between and is that replaces the
task by a new task , which has a frequency of 4 in .
Note that has a new output port, , but also uses the same
output port as . Moreover, has a new driver , which
connects the output port of to the input port , the sensor
port to , and the output port of to . The task in
mode has the same frequency and uses the same driver as
in mode . The period of , which determines the length of
each round, is again 10 ms. This means that in mode , the
task is invoked once per round, every 10 ms; the task is
5
Fig. 7. The time line for a round of mode .
Fig. 8. A mode .
invoked 4 times per round, every 2.5 ms; and the actuator
is updated once per round, every 10 ms.
A mode switch describes the transition from one mode to
another mode. For this purpose, a mode switch specifies a
switch frequency, a target mode, and a driver. Figure 9 shows
a mode switch from mode to target mode with the
switch frequency and the driver . The guard of
the driver is called the exit condition, as it determines whether
or not the switch occurs. The exit condition is evaluated
periodically, as specified by the switch frequency. As usual,
the switch frequency of 2 means that the exit condition of
is evaluated every 5 ms, in the middle and at the end of each
round of mode . The exit condition is a boolean-valued
condition on sensor ports and the mode ports of . If the
exit condition evaluates to true, then a switch to the target
mode is performed. The mode switch happens by executing
the driver , which provides values for all mode ports of ;
specifically, loads the constant into , the value of the
mode port into , and ensures that , , and keep
their values (this is omitted from Figure 9 to avoid clutter).
Like all drivers, mode switches are performed in logically zero
Fig. 9. A mode switch from mode to mode .
time.
Figure 10 shows the time line for the mode switch
performed at time . The program is in mode until
and then enters mode . Note that until time the time line
corresponds to the time line shown in Figure 7. At time ,
first the invocation of task is completed, then the mode
driver is executed. This finishes the mode switch. All
subsequent actions follow the semantics of the target mode
independently of whether the program entered just now
through a mode switch, at 5 ms into a round, or whether it
started the current round already in mode . Specifically, the
driver for the invocation of task is executed, still at time .
Note that the output port of has just received the value
of the output port from task by the mode driver . At
time , task is invoked a second time, and at time , the
round is finished, because this is the earliest time after the
mode switch at which a complete new round of mode can
begin. Now the input port of task is loaded with the
constant from the mode port . In this way, task can
detect that a mode switch occurred.
A mode switch may occur while a task is logically running;
in this case we say that the mode switch logically interrupts the
task invocation. For a mode switch to be legal, the target mode
is constrained so that all task invocations that may be logically
interrupted by a mode switch can be continued in the target
mode. In our example, the mode switch can occur at 5 ms
into a round of mode , while the task is logically running.
Hence the target mode must also invoke . Moreover, since
the period of
is 10 ms, as for mode , the frequency
of in must be identical to the frequency of in ,
namely, 1. If, alternatively, the period of were 20 ms, then
the frequency of in would have to be 2.
III. FORMAL DEFINITION OF GIOTTO
A. Syntax
Rather than specifying a concrete syntax for Giotto, we
formally define the components of a Giotto program in a more
abstract way. In practice, Giotto programs can be written in a
concrete, C like syntax.
A Giotto program consists of the following components:
1) A set of port declarations. A port declaration
consists of a port name , a type ,
and an initial value . We require that all
port names are uniquely declared; that is, if
and are distinct port declarations, then .
6
Fig. 10. The time line for the mode switch at time .
The set of declared port names is partitioned
into a set of sensor ports, a set
of actuator ports, a set of task input ports, a
set of task output ports, and a set
of task private ports. Given a port , we use
notation such as
for the type of , and for
the initial value of . A valuation for a set of
ports is a function that maps each port
to a value
in
. We write for the set of valuations
for .
2) A set of task declarations. A task declaration
consists of a task name , a set
of input ports, a set of output
ports, a set of private ports, and a
task function : . If
and are distinct
task declarations, then we require that and
. Tasks may share output
ports as long as the tasks are not invoked in the same
mode; see below. We write for the set of declared
task names.
3) A set of driver declarations. A driver declaration
consists of a driver name , a set
of source ports, a driver guard : ,
a set of destination ports, and a driver
function : . When the driver is
called, the guard is evaluated, and if the result is true,
then the function is executed. We require that all driver
names are uniquely declared, and we write for
the set of declared driver names.
4) A set of mode declarations. A mode declaration ( , ,
, , , ) consists of a
mode name , a positive mode period , a set
of mode ports, a set
of task invocations, a set of actuator updates,
and a set of mode switches. We require that all
mode names are uniquely declared, and we write
for the set of declared mode names.
a) Each task invocation
consists of a task frequency , a task
such that ,
and a task driver such that
and .
The invoked task
only updates mode and private
ports; the task driver reads only mode and sensor
ports, and updates the input ports of
. If and
are distinct task invocations in ,
then we require that ; that is,
tasks sharing output ports must not be invoked in
the same mode.
b) Each actuator update con-
sists of an actuator frequency , and an
actuator driver such that
and . The actua-
tor driver reads only mode ports, no sensor ports,
and updates only actuator ports. If
and
are distinct actuator updates in , then
we require that ; that is, in
each mode, an actuator can be updated by at most
one driver.
c) Each mode switch
consists of a mode-switch frequency ,
a target mode , and a mode driver
such that
and . The
mode driver reads only mode and sensor ports,
and updates the mode ports of the target mode .
If and are distinct mode switches
in , then we require that for all val-
uations either or
. It follows that all mode switches
are deterministic.
5) A start mode .
The program is well-timed if for all modes ,
all task invocations , and all mode
switches , if ,
7
then there exists a task invocation
with . The well-timedness condi-
tion ensures that mode switches do not terminate tasks: if a
mode switch occurs when a task is logically running, then the
same task must be present also in the target mode.
B. Semantics
A program configuration
consists
of a mode , a mode time , a valuation
for all ports, a set of active tasks,
and a time stamp . The set contains
all tasks that are logically running, whether or not they are
physically running by expending CPU time. The number
measures the amount of time that has elapsed since the last
mode switch, unless some tasks were logically running at the
time of the last mode switch, in which case “dates back” the
mode switch to the closest time instant before the mode switch
when the current mode could have started from its beginning
with all its tasks. For a program configuration
and a set
, we write for the valuation in that
agrees with on the values of all ports in .
The mode frequencies of a mode include (i) the
task frequencies for all task invocations
, (ii) the actuator frequencies for all actuator
updates , and (iii) the mode-switch
frequencies
for all mode switches
. Let be the least common multiple of
the mode frequencies of . During an execution, as long
as the program is in mode , the program configuration is
updated every time units. Each update results
from a sequence of five types of events: first, some tasks are
completed (i.e., removed from the active set); second, some
actuators are updated; third, some sensors are read; fourth, a
mode switch may occur; fifth, some new tasks are activated.
Let us be more precise. Consider a program configuration
. We need the following auxiliary
definitions:
A task invocation is completed
at configuration if , and is an integer
multiple of .
An actuator update is evalu-
ated at configuration if is an integer multiple of
.
A mode switch is evalu-
ated at configuration if is an integer multiple of
.
A task invocation is evalu-
ated at configuration if is an integer multiple of
.
The actuator update , mode switch , or
task invocation is enabled at configuration if it
is evaluated at and .
The program configuration is a successor configu-
ration of if results from by the following nine
steps, called Giotto micro steps. These are the steps a Giotto
program performs whenever it is invoked, initially with ,
, and :
1) [Update task output and private ports] Let
be the set of tasks such that a task invocation of the
form is completed at configura-
tion
. Consider a port . If
for some task , then
define ; otherwise,
define . This gives the new values of
all task output and private ports. Note that ports are
persistent in the sense that they keep their values unless
they are modified. Let
be the configuration that
agrees with on the values of ,
and otherwise agrees with .
2) [Update actuator ports] Consider a port .
If for some actuator update
that is enabled at configuration , then
define ; otherwise, de-
fine . This gives the new values of all
actuator ports. Let be the configuration that agrees
with on the values of , and otherwise
agrees with .
3) [Update sensor ports] Consider a port
.
Let be any value in ; that is, sensor
ports change nondeterministically. This is not done by
the Giotto program, but by the environment. All other
parts of a configuration are updated deterministically,
by the Giotto program. Let be the configuration
that agrees with on the values of , and
otherwise agrees with .
4) [Update mode] If a mode switch
is enabled at configuration , then
define ; otherwise, define . This
determines if there is a mode switch. Recall that at most
one mode switch can be enabled at any configuration.
Let be the configuration with mode that
otherwise agrees with .
5) [Update mode ports] Consider a port . If
for some mode switch
that is enabled at configuration , then define
; otherwise, define
. This gives the new
values of all mode ports of the target mode. Note that
mode switching updates also the output ports of all tasks
that are logically running. This does not affect the
execution of . When completes, its output ports are
again updated, by . Let be the configuration
that agrees with on the values of , and
otherwise agrees with .
6) [Update mode time] If no mode switch in
is enabled at configuration , then define .
Otherwise, suppose that a mode switch is enabled at con-
figuration to the target mode . Let
. If , then define .
Otherwise, let be the least common multiple of the set
for some
of task periods for running tasks; then is the
time it takes during a round of mode to complete all
running tasks simultaneously. Let be the least integer
multiple of such that ; then is the time
8
Fig. 11. The abstract syntax of a Giotto program with two modes.
until the next simultaneous completion point. Define
. Thus a mode switch always jumps
as close as possible to the end of a round of the target
mode. Let
be the configuration with mode time
that otherwise agrees with .
7) [Update task input ports] Consider a port .
If for some task invocation
that is enabled at configuration , then
define ; otherwise,
define . This gives the new values
of all task input ports. Let be the configuration
that agrees with on the values of , and
otherwise agrees with
.
8) [Update active tasks] Let be the set of tasks
such that a task invocation of the form
is enabled at configuration . The new
set of active tasks is
. Let be the configuration with the set
of active tasks that otherwise agrees with .
9) [Advance time] Let be the least integer multiple of
such that ; this is the time of
the next event (task invocation, actuator update, or mode
switch) in mode . The next time instant at which the
Giotto program is invoked is time units in
the future; an implementation may use a timer interrupt
for this. Let . Let be the
configuration with mode time and time stamp
that otherwise agrees with .
An execution of a Giotto program is an infinite se-
quence of program configurations such that
(i) with for all ports
, and (ii) is a successor configuration of
for all . Note that there can be a mode switch at the
start time of the program, but there can never be two mode
switches in a row without any time passing.
C. Example
We use the simple Giotto program from Figure 11 to illus-
trate Giotto’s semantics. This program contains two modes,
and . Mode has a period of 6 ms, and invokes
two tasks,
and , with frequencies of 1 and 2, respectively.
Mode has a period of 12 ms, and invokes and the task
, with frequencies of 2 and 3, respectively. The tasks
and both read the sensor port and write to the same
output port . This is possible because and are invoked
in different modes. The task reads and writes to the
output port , which is read by the actuator driver to write
the actuator port . In both modes the actuator update occurs
every 6 ms. Mode evaluates a possible mode switch to
mode every 3 ms; contemplates switching back to
every 4 ms. These mode switches are controlled by the driver
, which reads the sensor port . A mode change occurs if
contains the value 1. Both mode switches, when enabled,
write the ports and . We assume that with the exception
of , the guards of all other drivers are always true. The
initial values of the sensor and input ports are omitted from
the figure, as they are written before being read.
To illustrate the semantics of this program, consider an
execution that begins with the following
9
Fig. 12. The time line for an execution of the program from Figure 11.
program configurations:
The execution starts in mode , but switches immediately
to mode . At configuration , the execution switches back
to mode (note that a mode switch in a configuration
is reflected only in the successor configuration ). The
execution remains in mode until configuration .
Figure 12 shows an initial segment of the time line for
.
At 0 ms, the port is used to update the actuator port . The
sensor port is read by the mode driver . The guard of
evaluates to true, indicating a mode change, and thus the
port is updated (port is also updated but not used, and
therefore omitted in the figure). Port provides the input
to task . The sensor provides the input to task . At
4 ms, task completes; the sensor port is updated, but
no mode change occurs; and the sensor provides input to
a new invocation of task . At 6 ms, task completes; the
actuator port is updated using the output of ; and a new
invocation of task starts. At 8 ms, task completes; sensor
is updated; and the guard of the mode driver evaluates
to true, indicating a switch to mode and updating ports
and (neither port is used, and therefore both are omitted in
the figure). At 9 ms, sensor is updated again, but no mode
change occurs; sensor is updated; and an invocation of task
begins. At 12 ms, both tasks and complete; , ,
and are all updated; and new invocations of and start.
Note that at the time of the mode switch at 8 ms, the mode
time of the target mode is 2 ms, because task has been
logically running for 2 ms. For the duration of 1 ms, task
is the only running task, until at mode time 3 ms (real time
9 ms), an invocation of task is added. At mode time 6 ms
(real time 12 ms), the partial round of mode is finished,
and a new round begins.
IV. PLATFORM CONSTRAINTS FOR GIOTTO
In order to compile a Giotto program, the compiler needs
two additional pieces of information: (i) a platform specifica-
tion, which defines the number and topology of hosts (CPUs),
and worst-case execution times for all Giotto activities (tasks,
drivers, and sensor readings); and (ii) a jitter tolerance, which
specifies how much the actual timing can deviate from the
Giotto semantics. The jitter tolerance is needed because it may
be impossible to implement the Giotto semantics exactly. For
example, if according to Giotto semantics, several actuators
are written at the same point
in time, and there is only
one host, then the actual writes cannot all occur exactly
at time . The Giotto compiler takes a Giotto program, a
platform specification, and a jitter tolerance, and if possible,
generates platform code that lies within the jitter tolerance of
Giotto semantics. Specifically, for every program execution,
the compiler must attempt to produce a schedule that indicates
when and where the Giotto activities are performed. Such a
schedule may not exist, because the scheduling problem can be
overconstrained. An overconstrained scheduling problem may
become solvable without changing the Giotto program, by a
combination of the following: increase the number of hosts,
decrease the worst-case execution times, or increase the jitter
tolerance.
A. Scheduling Giotto
We define an abstract Giotto scheduling problem. The
problem is abstract, as we include only scheduling constraints
that need to be met by all Giotto implementations. Any
particular, concrete implementation may have to take into
account additional scheduling constraints.
Jobs. Let be a Giotto program. A job of is a pair
consisting of a job action and a job instance , chosen
from some index set . We distinguish between computation
jobs and communication jobs. The action of a computation job
is either a task , or or for a driver
, or for a sensor port . The
10
action executes the task ; the actions and
represent the execution of driver in cases where the outcome
of the driver guard is true or false, respectively; the action
loads a new sensor value into the port . We write
for the set of computation actions. For every computation
action , the set of read ports and the
set
of written ports are defined as follows:
If for , then and
.
If , then and .
If , then and .
If , then and .
The action of a communication job has the form
, for
a port , and its purpose is to broadcast the value of
over a network to all hosts of the platform. Other models of
communication are possible, but not addressed here.
Let be an execution of . For each
position and , we write for the
program configuration obtained from by performing the
Giotto micro steps 1 through , as defined in Section III-B. The
execution
gives rise to a set of computation jobs. For
these jobs we use the index set
,
where the index refers to the program configuration .
We write for the lexicographic order on ; that is,
if either , or both and
. The set is the smallest set of jobs containing the
following:
[Task jobs] If is a task invocation that is completed
at configuration , then .
[Actuator jobs] If is an actuator update that is
enabled at configuration , then .
If is evaluated but not enabled at , then
.
[Sensor jobs] If is a mode switch that is evaluated
at configuration , or is a task invocation that
is evaluated at configuration , and for a
sensor port , then .
[Mode-driver jobs] If is a mode switch that is
enabled at configuration , then . If
is evaluated but not enabled at configuration ,
then .
[Task-driver jobs] If is a task invocation that is
enabled at configuration , then .
If is evaluated but not enabled at , then
.
The jobs in are called the computation jobs induced by
the execution of the program .
The interaction between the jobs in constrains the order
in which these jobs can be performed: if job supplies a
value to job via a port, then must finish before can
begin. For two jobs and in and
a port , we say that writes to (in symbols,
) if (i) and , and (ii) there is
no job in such that and
. We write if there is some port such that
. Note from the definition of that a task job is
added to
with set to the configuration number of the job’s
completion in order to make the relation capture the fact
that the output ports of are written when the task completes.
Figure 13 shows the precedence constraints between the jobs
in .
Platform specifications. A Giotto program can in principle
be run on a single sufficiently fast CPU, independent of the
number of modes and tasks. However, taking into account
performance constraints, the timing requirements of a program
may or may not be achievable on a single CPU. We therefore
consider distributed platforms. For simplicity, we restrict our
attention to platforms that connect a set of hosts through a
broadcast channel, called the network; for example, all hosts
may be on a common bus. A platform specification for the
program
is a triple :
is a finite set of hosts, which represent the process-
ing elements on which computation jobs may execute. We
write
for the set of hosts together
with the network, which is denoted .
: is a function that assigns to
each pair , where is a computation action and
is a host, a worst-case execution time, which represents
an upper bound on the time required for processing a
job of the form on host . For driver jobs of the
form , the worst-case execution time takes
into account both the guard and the function of driver ;
for driver jobs of the form , only the driver
guard. Methods for obtaining worst-case execution times
can be found, for example, in [6], [7].
: is a function that assigns to each port
a worst-case communication time, which represents an
upper bound on the time required for broadcasting the
value of over the network.
Jitter tolerance. A jitter tolerance
is a positive
rational number. Intuitively, represents the maximal tolerable
difference between the actual time of an actuator write (or
sensor read), and the time at which the write (or read) is
supposed to occur according to the Giotto semantics. In
particular, if Giotto specifies an actuator write at 12 ms, then
an implementation that conforms with the jitter tolerance
must write the actuator in the interval ; and if
Giotto specifies a sensor read at 12 ms, then a conforming
implementation must read the sensor in the interval
(cf. Figure 13).
Schedules. A schedule specifies a possible timing for the
jobs that are induced by a program execution. Formally, a
schedule of the program on the set is a function
: that maps every time and
host (including the network) to a job in some
set . An element in may represent a computation or
communication job of , or a non-Giotto activity. We require
that jobs do not migrate between hosts: if ,
then . We also require that schedules are finitely
11
Fig. 13. The precedence and timing constraints for computation jobs.
varying: for all , there is no bounded infinite
sequence of reals such that
.
Given a schedule and job , we say that occurs in
if there exist and such that ;
in this case, we define and the following:
The start time of the job in the schedule
is . The start time may be .
The finish time of the job in the schedule is
. The finish time may be .
The execution time of the job in the schedule
is . The execution time may be
infinite.
Let be an execution of the program , and let be
a platform specification for . The schedule realizes the
program execution on a platform specified by if the
following conditions hold:
[Computation jobs] Every job occurs in and
. Second, if and ,
then . Third, for all jobs
, if and , then
.
[Communication jobs] For all jobs , if
and , then there exists a com-
munication job such that (i) occurs
in and , (ii) , and
(iii) and . In
this case, we say that is a communication predecessor
of .
Note that because is a schedule, rather than an actual run of
the Giotto program, it allocates the worst-case execution time
for each computation job, and the worst-case communication
time for each communication job. The schedule conforms
to the jitter tolerance if the following conditions hold:
[Actuator timing] For every actuator job
or in , where is an actuator driver,
we have and . Here is
the time stamp of the -th configuration of the program
execution .
[Sensor timing] For every sensor job
in , where is a sensor port, we have
and .
Given a Giotto program , a platform specification ,
and a jitter tolerance , a scheduling function maps every
execution of to a schedule that realizes on in
conformance with . The scheduling function is feasible if
for any two executions and that agree on the values of all
sensor ports up to time , the schedules and are iden-
tical up to time
; more precisely, if and
and
for all , then for all
and all , where is the time stamp of configura-
tion . Feasibility rules out clairvoyant scheduling functions,
which can predict future sensor values. The abstract Giotto
scheduling problem asks, given
, , and , if there exists
a feasible scheduling function. If not, then the scheduling
problem is overconstrained.
The scheduling constraints presented in this section are
intended to capture a minimal set of constraints: precedences,
sensor and actuator timing, and execution and communication
times. These constraints are necessary for any implementation
of Giotto, but they may not be sufficient. For example, a par-
ticular implementation may restrict the amount of information
on which a scheduler can base its decisions (according to
our definitions, a scheduling decision may depend on all past
sensor values), or it may bound the buffer size for storing
previous values of a port (according to our definitions, a
schedule may send any number of values of a port over the
network before any of the values is used), or it may require
the transmission of mode-change messages between hosts, etc.
By considering the constraints of concrete implementations,
the abstract Giotto scheduling problem can be refined into a
number of different concrete scheduling problems.
B. Giotto annotations
An ideal compiler must solve a Giotto scheduling problem
by producing a feasible scheduling function or determining
that the given problem instance is overconstrained. How-
ever, for distributed platforms, the abstract Giotto scheduling
problem is NP-hard (it is a generalization of multiprocessor
scheduling [8]). Algorithms and heuristics for solving similar
distributed scheduling problems can be found, for example, in
[9], [10], [11], [12]. In practice, a compiler will have a third
outcome, namely, that it succeeds neither in generating code
nor in proving non-schedulability. In order to aid the compiler
in finding a feasible scheduling function in difficult situations,
we introduce the concept of Giotto annotations.
The most basic Giotto annotation is the mapping annotation.
A particular application may require that tasks be located
on specific hosts, e.g., close to the physical processes that
the tasks control, or on processors particularly suited for the
operations of the tasks. A mapping annotation can be used
to express such constraints, and also to reduce the size of
the space in which the compiler must look for a feasible
scheduling function. Let be a Giotto program, and let
be a platform specification for . A mapping annotation for
on is a partial function : that assigns
a host of to some computation actions of . The mapping
annotation is complete if the function is total. Consider
a schedule that realizes an execution of on . The
schedule conforms to the mapping annotation if for
all jobs , if and is defined, then
.
12
A more detailed Giotto annotation is the scheduling anno-
tation. The exact form of scheduling annotations depends on
the platform: a scheduling annotation specifies task priorities,
relative deadlines, or time slots, depending on whether the
underlying real-time operating system uses a priority-driven,
deadline-driven, or time-triggered scheduler. We choose an
uncomplicated platform —with preemptive priority scheduling
of tasks, and round-robin time-slice scheduling of messages
on the network— in order to demonstrate that a precise
definition of scheduling annotations is possible; more elab-
orate annotations would require longer definitions, but not
a fundamental change in approach. One can define partial
scheduling annotations, which leave some decisions to the
system scheduler, but for simplicity, we define only a complete
form of scheduling annotation. To be precise, a scheduling
annotation for the program
on a platform specified by
is a tuple :
[Mapping] The function : is a com-
plete mapping annotation for on .
[Task priorities] The function : assigns
a priority to every task.
[Communication times] For simplicity, we assume that
all communication proceeds in rounds, with each round
providing a time slot to every port. The value of a port
can be broadcast once per round, in the slot provided to .
Let be the number of ports. The function
: is a bijection that assigns
a slot number to every port. The positive rational
is the duration of each time slot. We assume that only one
broadcast is possible per time slot; that is,
for all ports .
Consider a schedule that realizes an execution of
on . The schedule conforms to the scheduling annotation
if conforms to the mapping annotation
and the following conditions hold:
[Task priorities] Consider a job that occurs in the
schedule . The job is completed in at time if
. The job is enabled in at time if
for all jobs that occur in , if or is a
communication predecessor of , then is completed
at . For all times , all hosts , and
all task jobs and in , if
and and is enabled in
at time , then .
[Communication times] For every communication job
that occurs in , there exists a round
number such that
and .
A Giotto program with annotations is a formal refinement of
the program: the Giotto semantics, as defined in Section III-B,
is not changed by the annotations, but the number of feasible
scheduling functions may be reduced. The annotated Giotto
scheduling problem asks, given a Giotto program , a platform
specification , a jitter tolerance , and a (mapping or schedul-
ing) annotation , if there is a feasible scheduling function
such that for every execution of , the schedule
conforms to the annotation . If the abstract Giotto scheduling
problem has a solution, but the annotated problem
does not, then the annotation is invalid. Invalid
annotations constrain the program in a way that rules out all
feasible scheduling functions.
Mapping and scheduling annotations, as defined above,
provide only one example of how a Giotto program can
be mapped onto a particular kind of platform. According
to the definitions, mapping annotations occur strictly prior
to scheduling annotations. In general, we believe that it is
advantageous to arrange Giotto annotations in multiple levels.
Such a structured view supports the incremental refinement of
a Giotto program into an executable image. The multilayered
approach suggests a modular architecture for the Giotto com-
piler with separate modules for, say, mapping and scheduling.
The compiler may attempt to solve the scheduling problem on
any annotation level, and if it fails to do so, it may ask for
more detailed annotations at a lower level. At every level, the
annotation must be checked for validity, that is, for consistency
with the annotations at the higher levels and with the Giotto
semantics. Such a compiler can be evaluated along several
dimensions: (i) how many annotations it requires to generate
code, and (ii) what the cost is of the generated code. For
instance, a compiler can use a cost function that minimizes
jitter of the actuator updates.
C. Example
To illustrate the flexibility afforded to the Giotto compiler,
we present several possible schedules for an execution of the
Giotto program from Figure 11. The platform specification
consists of a single host
and the following worst-case execution times:
Since is a singleton set, we need not define . The
jitter tolerance is .
Consider the sample execution pictured in Figure 12.
In , sensors are read and actuators are written at precisely the
time instants specified by the Giotto semantics. This precision
is clearly impossible to attain if sensor reads and actuator
writes take a non-negligible amount of time. Further, in ,
the second invocation of task executes between 6 and
12 ms. This requirement may be too strict, and if insisted upon
would prevent some Giotto programs from being schedulable.
Instead, what is required is that the second invocation of
executes after all its input port values are available, and before
any job that needs its output port values.
Figure 14 shows the constraints on timing and precedences
for the computation jobs that are induced by the execution ;
13
Fig. 14. The precedence and timing constraints for the program execution of Figure 12. Here is an abbreviation for . Similarly,
are, respectively, abbreviations for , , , , , and .
Fig. 15. A schedule for the program execution of Figure 12.
Fig. 16. A second schedule for the program execution of Figure 12.
14
Fig. 17. A third schedule for the program execution of Figure 12.
these are the constraints that appear in the definition of the
realization of an execution, and in the definition of confor-
mance with the jitter tolerance. Boxes with a double border
represent sensor and actuator jobs. These jobs are special,
because their execution is constrained to happen at specific
times. The remaining boxes are jobs that execute tasks, mode
drivers, and task drivers. These jobs may execute at any time,
provided they meet all precedence constraints. For example,
precedes , because the sensor job
provides the sensor value to the task-driver job
. Not also that in Figure 14 jobs of the form
do not precede other jobs, as a driver does not
write any ports if its guard evaluates to false.
Figure 15 shows a schedule that realizes the execution
on a platform specified by and conforms to the jitter
tolerance . To understand what Figure 15 represents,
consider the interval from to . First the actuator job
executes; this job updates the actuator port .
Then the sensor jobs and execute;
these jobs update the sensor ports and . Next, the
mode-driver job executes, indicating a mode
change, followed by the task-driver jobs and
. Finally, the task jobs and , cor-
responding to the first invocations of tasks and , execute.
Note that the driver job for the second invocation of task
, namely , as well as the task itself, ,
execute in advance of 6 ms. This is permissible, because
needs only the value of port produced by
the first invocation of task , which is complete at
3.5 ms. The schedule of Figure 15 conforms to a scheduling
annotation with ; for example, at
2.25 ms and are both enabled, but
executes.
Figure 16 shows a second schedule that realizes the exe-
cution on a platform specified by and conforms to the
jitter tolerance . The schedule of Figure 16 conforms
to a scheduling annotation with .
Figure 17 shows a third schedule for the same execution,
conforming to a scheduling annotation with
. In this schedule, task is preempted at 2.5 ms
by the driver for task and then by task itself.
V. DISCUSSION
While many of the individual elements of Giotto are derived
from the literature, we believe that the study of strictly time-
triggered task invocation together with strictly time-triggered
mode switching as a possible organizing principle for abstract,
platform-independent real-time programming is an important
step towards separating reactivity from schedulability. The
term reactivity expresses what we mean by control-systems as-
pects: the system’s functionality, in particular, the control laws,
and the system’s timing requirements. The term schedulability
expresses what we mean by platform-dependent aspects, such
as platform performance, platform utilization (scheduling), and
fault tolerance. Giotto decomposes the development process
of embedded control software into high-level real-time pro-
gramming of reactivity and low-level real-time scheduling of
computation and communication. Programming in Giotto is
real-time programming in terms of the requirements of control
designs, i.e., their reactivity, not their schedulability.
15
The strict separation of reactivity from schedulability is
achieved in Giotto through time- and value-determinism: given
a real-time trace of sensor valuations, the corresponding real-
time trace of actuator valuations produced by a Giotto program
is uniquely determined [5]. The separation of reactivity from
schedulability has several important ramifications. First, the
reactive (i.e., functional and timing) properties of a Giotto
program may be subject to formal verification against a
mathematical model of the control design [13]. Second, a
Giotto program specifies reactivity in a modular fashion, which
facilitates the exchange and addition of functionality. For
example, functionality code (i.e., tasks and driver functions)
can be packaged as software components and reused. Third,
as increasingly powerful Giotto compilers become available,
the embedded-software development effort is significantly
reduced. The tedious programming of scheduling code is
replaced by compilation, which eliminates a common source
of errors. Fourth, Giotto is compatible with any scheduling
strategy, which therefore becomes a parameter of the Giotto
compiler. There are essentially two reasons why even the
best Giotto compiler may fail to generate executable code:
(i) not enough platform utilization, or (ii) not enough platform
performance. Then, independently of the program’s reactivity,
utilization can be improved by a better scheduling module,
and performance can be improved by faster or more parallel
hardware or leaner functionality code.
A. Current Giotto implementations
We briefly review the existing Giotto implementations. The
first implementation of Giotto was a simplified Giotto run-time
system on a distributed platform of Lego Mindstorms robots.
The robots used infrared transceivers for communication. Then
we implemented a full Giotto run-time system on a distributed
platform of Intel x86 robots running the real-time operating
system VxWorks. The robots used wireless Ethernet for com-
munication. We also implemented a Giotto program running
on five robots, three Lego Mindstorms and two x86-based
robots, to demonstrate Giotto’s applicability for heterogeneous
platforms. The communication between the Mindstorms and
the x86 robots was done by an infrared-Ethernet bridge
implemented on a PC. For an informal discussion of these
implementations, and embedded control-systems development
with Giotto in general, can be found in [14].
In collaboration with Marco Sanvido and Walter Schaufel-
berger at ETH Z
¨
urich, we built a high-performance imple-
mentation of a Giotto system on a single StrongARM SA-
110 processor that controls an autonomously flying model
helicopter [15]. We started from an existing implementation of
the helicopter control system [16], which included a custom-
designed real-time operating system called HelyOS and con-
trol software written in a subset of Oberon [17] suited for
embedded real-time systems. We reimplemented the existing
software as a combination of a Giotto program and Oberon
code that implements the task and driver functions. Much of
the existing functionality code could be reused. The Giotto
program for the helicopter consists of six Giotto modes such as
“take-off” and “hover.” The hover mode, for example, contains
a 40 Hz controller task and a 200 Hz data-fusion task.
For this project, we developed a Giotto compiler that targets
a virtual real-time machine, called the Embedded Machine [5].
Embedded Machine code, also called E code, supervises the
timing of functionality code, which can be written in any
conventional programming language such as C. An Embed-
ded Machine-based Giotto run-time system consists of an
implementation of the Embedded Machine together with the
scheduler of a real-time operating system. While E code is
interpreted by the Embedded Machine, functionality code is
native code that is scheduled for execution by the system
scheduler. For E code that is generated from a Giotto source
program, the scheduling problem is more constrained than
the abstract Giotto scheduling problem defined in Section IV-
A, but still independent of any particular system scheduler;
it is only required that the scheduler be compatible with
the schedulability test of the Giotto compiler [18]. E code
produced by the compiler can be executed on any platform
for which an Embedded Machine implementation is available.
For the helicopter project, we implemented the Embedded
Machine on top of HelyOS.
We also implemented a Giotto-based electronic throttle
controller on a single Motorola MPC-555 processor running
the real-time operating system OSEKWorks. For this purpose,
we ported the Embedded Machine to OSEKWorks, which is
widely used in the automotive industry. In addition to these
real-time versions of the Embedded Machine, non-real-time
implementations of the Embedded Machine are available for
Linux and Windows.
B. Related work
Giotto is inspired by the time-triggered architecture
(TTA) [4], which first realized the time-triggered paradigm for
meeting hard real-time constraints in safety-critical distributed
settings. However, while the TTA encompasses a hardware
architecture and communication protocols, Giotto provides a
hardware-independent and protocol-independent abstract pro-
grammer’s model for time-triggered applications. Giotto can
be implemented on any platform that provides sufficiently
accurate clock primitives or supports a clock synchronization
scheme. The TTA is thus a natural platform for Giotto pro-
grams.
Giotto is similar to architecture description languages
(ADLs) [19]. Like Giotto, ADLs shift the programmer’s
perspective from small-grained features such as lines of code
to large-grained features such as tasks, modes, and inter-
component communication, and they allow the compilation
of scheduling code to connect tasks written in conventional
programming languages. The design methodology for the Mars
system, a predecessor of the TTA, distinguishes in a similar
way “programming in the large” from “programming in the
small” [20]. The inter-task communication semantics of Giotto
is particularly similar to the MetaH language [21], [22], which
is designed for real-time, distributed avionics applications.
MetaH supports periodic real-time tasks, multimodal control,
and distributed implementations. Giotto can be viewed as
capturing a time-triggered fragment of MetaH in an abstract
and formal way. Unlike MetaH, Giotto does not constrain the
implementation to a particular scheduling scheme.
16
The goal of Giotto —to provide a platform-independent
programming abstraction for real-time systems— is shared
also by the synchronous reactive programming languages [3],
such as Esterel [23], Lustre [24], and Signal [25]. While
the synchronous reactive languages are designed around zero-
delay value propagation, Giotto is based on the formally
weaker notion of unit-delay value propagation, because in
Giotto, scheduled computation (i.e., the execution of tasks)
takes time, and synchronous computation (i.e., the execu-
tion of drivers) consists only of independent, non-interacting
processes. This decision shifts the focus and the level of
abstraction in essential ways. In particular, for analysis and
compilation, the burden for the well-definedness of values
is shifted from logical fixed-point considerations to physical
scheduling constraints (in Giotto all values are, semantically,
always well-defined). Thus, Giotto can be seen as identifying
a class of synchronous reactive programs that support typical
real-time control applications and efficient code generation [5].
Acknowledgments. We thank Rupak Majumdar for imple-
menting a prototype Giotto compiler for Lego Mindstorms
robots. We thank Dmitry Derevyanko and Winthrop Williams
for building the Intel x86 robots. We thank Edward Lee and
Xiaojun Liu for help with implementing Giotto as a “model
of computation” in Ptolemy II [26]. We thank Marco Sanvido
for his suggestions on the design of the Giotto drivers. We
thank Paul Griffiths for implementing the functionality code
of the electronic throttle controller.
REFERENCES
[1] D. Langer, J. Rauch, and M. R
¨
oßler, “Fly-by-wire systems for mili-
tary high-performance aircraft,” in Real-time Systems: Engineering and
Applications. Kluwer, 1992, pp. 369–395.
[2] R. Collinson, “Fly-by-wire flight control,” Computing and Control
Engineering, vol. 10, no. 4, pp. 141–152, 1999.
[3] N. Halbwachs, Synchronous Programming of Reactive Systems. Kluwer,
1993.
[4] H. Kopetz, Real-time Systems: Design Principles for Distributed Em-
bedded Applications. Kluwer, 1997.
[5] T. Henzinger and C. Kirsch, “The Embedded Machine: Predictable,
portable real-time code,” in Proc. of the Conference on Programming
Language Design and Implementation. ACM, 2002, pp. 315–326.
[6] S. Malik and Y.-T. Li, Performance Analysis of Real-Time Embedded
Software. Kluwer, 1999.
[7] H. Theiling, C. Ferdinand, and R. Wilhelm, “Fast and precise WCET
prediction by separated cache and path analyses,” Real-Time Systems,
vol. 18, no. 2–3, pp. 157–179, 2000.
[8] M. Garey and D. Johnson, Computers and Intractability: A Guide to the
Theory of NP-Completeness. Freeman, 1979.
[9] K. Tindell and J. Clark, “Holistic schedulability for distributed hard
real-time systems,” Microprocessing and Microprogramming, vol. 40,
pp. 117–134, 1994.
[10] P. Eles, K. Kuchcinski, Z. Peng, A. Doboli, and P. Pop, “Process schedul-
ing for performance estimation and synthesis of hardware/software
systems,” in Proc. of the EUROMICRO Conference. IEEE, 1998, pp.
168–175.
[11] P. Brucker, Scheduling Algorithms. Springer-Verlag, 2001.
[12] M. Pinedo, Scheduling: Theory, Algorithms, and Systems. Prentice-Hall,
2002.
[13] T. Henzinger, “Masaccio: A formal model for embedded components,”
in Proc. of the IFIP Conference on Theoretical Computer Science, vol.
1872 of Lecture Notes in Computer Science. Springer-Verlag, 2000,
pp. 549–563.
[14] T. Henzinger, B. Horowitz, and C. Kirsch, “Embedded control systems
development with Giotto,” in Proc. of the Conference on Languages,
Compilers, and Tools for Embedded Systems. ACM, 2001, pp. 64–72.
[15] C. Kirsch, M. Sanvido, T. Henzinger, and W. Pree, “A Giotto-based
helicopter control system,” in Proc. of the Intl. Workshop on Embedded
Software, vol. ??? of Lecture Notes in Computer Science. Springer-
Verlag, 2002.
[16] J. Chapuis, C. Eck, M. Kottmann, M. Sanvido, and O. Tanner, “Control
of helicopters,” Control of Complex Systems, pp. 359–392, 1999.
[17] N. Wirth and J. Gutknecht, Project Oberon: The Design of an Operating
System and Compiler. ACM, 1992.
[18] T. Henzinger, C. Kirsch, R. Majumdar, and S. Matic, “Time-safety
checking for embedded programs,” in Proc. of the Intl. Workshop on
Embedded Software, vol. ??? of Lecture Notes in Computer Science.
Springer-Verlag, 2002.
[19] P. Clements, “A survey of architecture description languages,” in Proc.
of the Intl. Workshop on Software Specification and Design. IEEE,
1996, pp. 16–25.
[20] H. Kopetz, R. Zainlinger, G. Fohler, H. Kantz, P. Puschner, and
W. Sch
¨
utz, “The design of real-time systems: From specification to im-
plementation and verification,” IEE/BCS Software Engineering Journal,
vol. 6, no. 3, pp. 72–82, 1991.
[21] S. Vestal and P. Binns, “Scheduling and communication in MetaH,” in
Proc. of the Real-time Systems Symposium. IEEE, 1993, pp. 194–200.
[22] S. Vestal, “MetaH support for real-time multi-processor avionics,” in
Proc. of the Joint Workshop on Parallel, Distributed, and Object-
Oriented Real-Time Systems. IEEE, 1997, pp. 11–21.
[23] G. Berry, “The foundations of Esterel,” in Proof, Language and Inter-
action: Essays in Honour of Robin Milner, G. Plotkin, C. Stirling, and
M. Tofte, Eds. MIT Press, 2000, pp. 425–454.
[24] N. Halbwachs, P. Caspi, P. Raymond, and D. Pilaud, “The synchronous
dataflow programming language Lustre,” Proc. of the IEEE, vol. 79,
no. 9, pp. 1305–1320, 1991.
[25] A. Benveniste, P. L. Guernic, and C. Jacquemot, “Synchronous program-
ming with events and relations: The Signal language and its semantics,”
Science of Computer Programming, vol. 16, no. 2, pp. 103–149, 1991.
[26] J. Davis, M. Goel, C. Hylands, B. Kienhuis, E. Lee, J. Liu, X. Liu,
L. Muliadi, S. Neuendorffer, J. Reekie, N. Smyth, J. Tsay, and Y. Xiong,
“Ptolemy II: Heterogeneous concurrent modeling and design in Java,”
University of California, Berkeley, Tech. Rep. UCB/ERL M99/44, 1999.
Thomas A. Henzinger is a Professor of Electrical
Engineering and Computer Sciences at the Univer-
sity of California, Berkeley. He holds a Dipl.-Ing.
degree in Computer Science from Kepler Univer-
sity in Linz, Austria, an M.S. degree in Computer
and Information Sciences from the University of
Delaware, and a Ph.D. degree in Computer Science
from Stanford University (1991). He was an Assis-
tant Professor of Computer Science at Cornell Uni-
versity (1992–95), and a Director of the Max-Planck
Institute for Computer Science in Saarbr
¨
ucken, Ger-
many (1999). His research focuses on formalisms and tools for the design,
implementation, and verification of reactive, real-time, and hybrid systems.
Benjamin Horowitz received his B.A. in Philosophy
from Wesleyan University in 1994, studied computer
science at the University of Massachusetts, Amherst
from 1995 to 1997, and since 1997 has been a Ph.D.
student in the Department of Electrical Engineering
and Computer Sciences at the University of Cali-
fornia, Berkeley. His research interests include real-
time programming languages, scheduling theory, and
the design of embedded systems.
17
Christoph M. Kirsch is a postdoctoral researcher
at the Department of Electrical Engineering and
Computer Sciences at the University of California,
Berkeley. He holds a Dipl.-Inform. degree (1996)
and a Ph.D. degree (1999) in Computer Science
from the University of the Saarland, Germany. He
received both degrees while at the Max-Planck Insti-
tute for Computer Science in Saarbr
¨
ucken, Germany.
His research focuses on formalisms and tools for
the design and implementation of real-time and
embedded systems.