Conference PaperPDF Available

Implicit state machines

Authors:

Abstract and Figures

Finite-state machines (FSM) are a simple yet powerful abstraction widely used for modeling, programming and verifying real-time and reactive systems that control modern factories, power plants, transportation systems and medical equipment. However, traditionally finite-state machines are either encoded indirectly in an imperative language, such as C and Verilog, or embedded as an imperative extension of a declarative language, such as Lustre. Given the widely accepted advantage of declarative programming, can we have a declarative design of finite-state machines to facilitate design, construction, and verification of embedded programs? By sticking to the design principle of declarativeness, we show that a novel abstraction emerges, implicit state machines, which is declarative in nature and at the same time supports recursive composition. Given its simplicity and universality, we believe it may serve as a new foundation for programming embedded systems.
Content may be subject to copyright.
Implicit State Machines
Fengyun Liu
Oracle Labs
Switzerland
fengyun.liu@oracle.com
Aleksandar Prokopec
Oracle Labs
Switzerland
aleksandar.prokopec@oracle.com
Abstract
Finite-state machines (FSM) are a simple yet powerful ab-
straction widely used for modeling, programming and ver-
ifying real-time and reactive systems that control modern
factories, power plants, transportation systems and medical
equipment.
However, traditionally nite-state machines are either en-
coded indirectly in an imperative language, such as C and
Verilog, or embedded as an imperative extension of a declar-
ative language, such as Lustre. Given the widely accepted
advantage of declarative programming, can we have a declar-
ative design of nite-state machines to facilitate design, con-
struction, and verication of embedded programs?
By sticking to the design principle of declarativeness, we
show that a novel abstraction emerges, implicit state ma-
chines, which is declarative in nature and at the same time
supports recursive composition. Given its simplicity and uni-
versality, we believe it may serve as a new foundation for
programming embedded systems.
CCS Concepts: Hardware
Software tools for EDA;
Software and its engineering
Domain specic lan-
guages.
Keywords: Finite-state machines, hierarchical nite-state
machines, implicit state machines
ACM Reference Format:
Fengyun Liu and Aleksandar Prokopec. 2022. Implicit State Ma-
chines. In Proceedings of the 23rd ACM SIGPLAN/SIGBED Interna-
tional Conference on Languages, Compilers, and Tools for Embedded
Systems (LCTES ’22), June 14, 2022, San Diego, CA, USA. ACM, New
York, NY, USA, 13 pages. hps://doi.org/10.1145/3519941.3535065
1 Introduction
Finite-state machines are a universal formalism for modeling,
programming and verifying real-time and reactive systems,
Permission to make digital or hard copies of all or part of this work for
personal or classroom use is granted without fee provided that copies are not
made or distributed for prot or commercial advantage and that copies bear
this notice and the full citation on the rst page. Copyrights for components
of this work owned by others than ACM must be honored. Abstracting with
credit is permitted. To copy otherwise, or republish, to post on servers or to
redistribute to lists, requires prior specic permission and/or a fee. Request
permissions from permissions@acm.org.
LCTES ’22, June 14, 2022, San Diego, CA, USA
©2022 Association for Computing Machinery.
ACM ISBN 978-1-4503-9266-2/22/06.. .$15.00
hps://doi.org/10.1145/3519941.3535065
and are widely used in industiral automation, public trans-
portation systems, medical equipment, as well as avionics.
While many imperative languages, such as C and Ver-
ilog, support nite-state machines via encoding, it is more
advantageous to have nite-state machines as a language
construct to facilitate design, construction, and verication
of embedded systems.
However, most such programming models of nite-state
machines are in an imperative style, instead of being declara-
tive [
14
,
27
]. It is well known that declarative programming
bridges the gap of specication and implementation, facil-
itates program transformation and verication, and at the
same time less error-prone than imperative programming
[
15
,
18
,
20
,
22
,
26
,
33
]. We therefore ask the following ques-
tion:
Can we have a declarative design of nite-
state machines to facilitate design, construc-
tion, and verication of embedded systems?
The main idea of this paper is to show that by adhering to
the design principle of declarativeness, we discover a novel
abstraction, which we call implicit state machines, and which
answers the question above armatively.
At the high-level, implicit state machines is based on the
following observations about FSMs: (1) state transitions do
not have to be explicitly enumerated state by state; (2) state
transition is a function; and (3) the inputs of the state ma-
chines do not need to be declared explicitly (Section 2).
Our contributions are listed below:
Following the design principle of declarativeness, we
discover a novel abstraction, implicit state machines,
which are simple, exible, universal and recursively
composable.
We formalize the concept of implicit state machines in
a core calculus specialized with the domain of Boolean
algebra. We show that it can serve as a simple and
elegant model for sequential digital circuits, which is
not known previously.
We develop an embedded DSL in Scala for digital de-
sign based on implicit state machines, and we assess
its practicality by designing a micro-controller in the
DSL.
2 Deriving Implicit State Machines
Readers may skip this section and jump to the intuitive intro-
duction of implicit state machines on the rst read (Section 3).
LCTES ’22, June 14, 2022, San Diego, CA, USA Fengyun Liu and Aleksandar Prokopec
Mathematically, a nite state machine is usually repre-
sented as a quintuple (𝐼 , 𝑆, 𝑠 0, 𝜎, 𝑂 )1:
𝐼is the set of inputs;
𝑆is the set of states;
𝑠0𝑆is the initial state;
𝜎
:
𝐼×𝑆𝑆×𝑂
maps the input and the current state
to the next state and the output;
𝑂is the set of outputs.
FSM can also be represented graphically by state-transition
diagrams, as the following gure shows:
𝑞1
start 𝑞2𝑞3
0/1
1/0
1/1
0/0
0/1, 1/1
In the state machine above,
𝑞1
is the initial state, and each
edge denotes a state transition: the label 0
/
1on the edge
means the transition happens when the input is 0, and it
outputs 1when the transition occurs.
Implicit state machines are based on a reection on the
essence of FSMs: a mapping from input and state to the next
state and output.
Insight 1. The rst insight towards implicit state ma-
chines is that state transitions do not need to be explicitly
enumerated, as it is taken for granted in existing languages
for programming with FSMs [12,14,21,27].
In a declarative language, the mapping can be represented
by any expression. This gives us a tentative representation
as follows:
𝜆𝑥:𝐼×𝑆. (𝑡1, 𝑡2):𝐼×𝑆𝑆×𝑂
The body
(𝑡1, 𝑡2)
enforces that the output and next state
are implemented as two functions. This imposes unnecessary
syntatic constraints. If we introduce tuples in the language,
we can replace (𝑡1, 𝑡2)just by 𝑡:
𝜆𝑥:𝐼×𝑆 . 𝑡 :𝐼×𝑆𝑆×𝑂
Insight 2. The second insight is that the state is neither
an input to an FSM nor an output of an FSM, but an internal
value. It leads us to the following representation with the
state variable 𝑠:
𝜆𝑥:𝐼 . fsm {𝑠𝑡}:𝐼𝑂
In the above, the term
𝑡
still has the type
𝑆×𝑂
. But seen
from outside, a state machine just maps input to output,
which corresponds to our intuition.
Insight 3. The last insight is that the inputs do not need to
be declared explicitly, they can be captured from the lexical
1
Technically, the quintuple described here is a Mealy machine, because it
has an output. In embedded systems, pristine FSMs without output are not
interesting.
D Q
(a) Circuit Symbol
S D S’ Q
0 0 0 0
0 1 1 0
1 0 0 1
1 1 1 1
(b) Truth table
Figure 1. D ip-ops and its semantics
D Q
1
D Q
2
D Q
3
D Q
4
Figure 2. A 4-bit serial-in serial-out shift register
scope, similar to capture in lambda calculus [3]:
fsm {𝑠𝑡}:𝑂
We still miss the initial state, so we use the value
𝑣
to
denote the initial state of the FSM:
fsm {𝑣|𝑠𝑡}:𝑂
After all these steps, nally we arrived at a declarative
representation of nite-state machines.
3 Implicit State Machines, Informally
Suppose we are working in the domain of digital circuits.
One of the most common state elements in digital circuits
are D ip-ops, whose symbol and truth-table semantics are
presented in Figure 1.
Intuitively, D ip-ops delay the input
𝐷
by one clock.
It can be seen from the truth table that the next state
𝑆
is
always equal to the input
𝐷
, and the output
𝑄
is always
equal to the current state 𝑆.
Using implicit state machines, a one-bit D ip-op with
an input signal 𝑑can be represented as follows:
fsm {0|𝑠 (𝑑, 𝑠 ) }
In the above, 0represents the initial state of the D ip-op;
𝑠
represents the current state;
𝑑
represents the input. The
body is a pair
(𝑑, 𝑠 )
, which means that the next state of the
implicit state machine is the input
𝑑
and the output is the
current state 𝑠.
Note that in the above, the state variable
𝑠
is bound, while
the input
𝑑
is not bound. This is a characteristic of implicit
state machines, where the inputs are implicit, i.e., they are
captured from the lexical environment, similar to capture in
lambda calculus [3].
D ip-ops can be use to implement shift registers. In
Figure 2, we implement a 4-bit serial-in serial-out shift regis-
ter by chaining 4 D ip-ops. As a single D ip-op delays
Implicit State Machines LCTES ’22, June 14, 2022, San Diego, CA, USA
D Q
1
D Q
2
D Q
3
D Q
4
Q1 Q2 Q3 Q4
Figure 3. A 4-bit serial-in parallel-out shift register
the input signal by one clock, intuitively the 4-bit serial-in
serial-out shift register delays the input signal by 4 clocks.
We implement the 4-bit serial-in serial-out shift register
for a given input 𝑑with implicit state machine as follows:
let q1 = fsm { 0 | s => (d, s) } in
let q2 = fsm { 0 | s => (q1, s) } in
let q3 = fsm { 0 | s => (q2, s) } in
let q4 = fsm { 0 | s => (q3, s) } in
q4
In the code above, we use the standard linguistic construct
let/in to introduce local bindings.
Implicit state machines are just expressions, thus they
may appear in any place where an expression is allowed.
In particular, we may nest them to get another equivalent
implementation of the 4-bit serial-in serial-out shift register:
fsm{0|s=>
letq1=fsm{0|s=>(d,s)}in
let q2 = fsm { 0 | s => (q1, s) } in
let q3 = fsm { 0 | s => (q2, s) } in
(q3, s)
}
An equivalent and simpler implementation of the 4-bit
serial-in serial-out shift register is shown below:
fsm { (0, 0, 0, 0) | s => ((d, s.1, s.2, s.3), s.4) }
In the above, we use the syntax
(𝑡, . . . , 𝑡 )
to represent a
tuple, and
𝑡.𝑖
to represent the
𝑖
-th component of the tuple
𝑡
.
In fact, we will show in the next section, there is a mechanic
transformation from all other equivalent representation to
this succinct form (Section 4.4).
There are also serial-in parallel-out shift registers, as shown
in Figure 3. They can be implemented with implicit state ma-
chines as follows:
let q1 = fsm { 0 | s => (d, s) } in
let q2 = fsm { 0 | s => (q1, s) } in
let q3 = fsm { 0 | s => (q2, s) } in
let q4 = fsm { 0 | s => (q3, s) } in
(q1, q2, q3, q4)
An equivalent and simpler implementation of the 4-bit
serial-in parallel-out shift register is shown below:
fsm { (0, 0, 0, 0) | s => ((d, s.1, s.2, s.3), s) }
We draw the readers’ attention to the following properties
of implicit state machines.
Declarativeness. In contrast to existing imperative pro-
gramming models with nite-state machines [
14
,
27
], im-
plicit state machines are declarative. As we will see in the
next section, the declarative nature of implicit state machines
facilitate transformation of programs, thanks to referential
transparency, which enables substitute equals for equals [
33
].
Simplicity. As we have seen in the example of D ip-ops,
compared to the textbook presentation of D ip-ops in the
form of truth tables, the representation based on implicit
state machines is much simpler and more intuitive. While
simple concepts can be explained in a complex way, we do
not see how implicit state machines could be reduced to a
simpler model.
Flexibility. Most existing programming models with -
nite state machines demand explicit enumeration of state
transitions [
12
,
14
,
21
,
27
]. In contrast, implicit state ma-
chines just do not mandate explicit enumeration of state
transitions in the program. However, they do not forbid that.
This means that programmers can continue to program with
explicit states when necessary. This is can be done by intro-
ducing a 𝑚𝑎𝑡𝑐ℎ-expression:
fsm{0|s=>
match (s, d) with
case (0, 0) => (0, 0)
case (0, 1) => (1, 0)
case (1, 0) => (0, 1)
case (1, 1) => (1, 1)
}
In the above, the
match
expression denes the semantics
of D ip-ops in the form of truth tables (Figure 1).
Recursive Composability. Implicit state machines are
recursively composable, which is a yardstick of proper lan-
guage design. Recursive composability corresponds to the
need for hierarchical decomposition in designing real-world
systems.
Universality. The universality of implicit state machines
are inherited from the universality of nite-state machines,
as the latter can be represented by the former.
4 Implicit State Machines, Formally
In this section, we formalize implicit state machines in a
small calculus with Boolean algebra as the domain intended
for digital design.
4.1 Syntax
The syntax of the calculus is presented below:
LCTES ’22, June 14, 2022, San Diego, CA, USA Fengyun Liu and Aleksandar Prokopec
𝑡::=terms
𝑎, 𝑏, 𝑐 external input
𝑥, 𝑦, 𝑧 , 𝑠 variables
𝑙𝑒𝑡 𝑥 =𝑡 𝑖𝑛 𝑡 let binding
𝛽Boolean value
𝑡𝑡1 bit and
𝑡+𝑡1 bit or
!𝑡1 bit not
(𝑡, . . . , 𝑡 )tuple
𝑡.𝑖 projection
fsm {𝑣|𝑠𝑡}implicit state machine
𝛽::=0|1Boolean values
𝑣::=𝛽| (𝑣, . . . , 𝑣 )values
𝑖::=0,1,2, . . . indexes
Beyond the basic elements of Boolean algebra, we also
introduce
𝑙𝑒𝑡
-bindings, which is a basic abstraction and reuse
mechanism. Tuples and projections are introduced for paral-
lel composition and decomposition. In a projection
𝑡.𝑖
, the
index
𝑖
must be a statically known number. For implicit state
machines, we require that the initial state is a value.
A circuit usually has external inputs, which are repre-
sented by variables
𝑎, 𝑏, 𝑐
. By convention, we use
𝑥, 𝑦 , 𝑧
for
𝑙𝑒𝑡
-bindings, and
𝑠
for the binding in implicit state machines.
We choose Boolean algebra as the domain theory, but
it can also be other mathematical structures, for example
natural numbers or tensors. Our transform does not assume
properties of mathematical structures as long as we may
substitute equals for equals [33].
To avoid technical details of same names in bindings, we
assume the uniqueness of bound variables, which can be
easily achieved via renaming.
4.2 Semantics
The semantics follows the synchronous hypothesis [
4
], which
assumes that the computation of the response to an input
takes no time. For synchronous digital circuits, it means that
the whole system produces an output at each clock tick.
The semantics of the language is dened with the help
of a state
𝜎
and an environment
𝜌
. The state
𝜎
maps a state
variable to a state value, the environment variable
𝜌
maps an
external input to a value. The big-step operational semantics
is dened with the following reduction relation:
𝑡𝜎,𝜌
𝑣|𝜎
It means that given the current state
𝜎
and environment
𝜌
, the term
𝑡
evaluates to the value
𝑣
with the next state
𝜎
.
The reduction rules are dened in Figure 4. We explain the
rules below:
E-Value. If the term is already a value, do nothing.
There are no nested state machines, thus the mapping
for the next state is the empty set.
E-Input. Look up the external variable
𝑎
from the
environment 𝜌.
E-Let. First evaluate
𝑡1
to the value
𝑣1
, then evaluate
𝑡2with 𝑥replaced by 𝑣1.
E-Tuple. Evaluate each component in parallel to a
value, and accumulate the mapping for the next state.
E-Project. First evaluate the term to a tuple value,
then return the corresponding component.
E-And. Evaluate the two components in parallel to
Boolean values, then call the helper method
𝑎𝑛𝑑
to
compute the resulting Boolean value
𝛽
. As each compo-
nent may contain implicit state machines, accumulate
the mapping for the next state.
E-Or. Similar as above, but use the helper function
𝑜𝑟
to compute the resulting value.
E-Not. Similar as above, but use the helper function
𝑛𝑜𝑡 to compute the resulting value.
E-Fsm. First look up the value for the current state
from the state map
𝜎
. Then evaluate the body of the
state machine to a pair value
(𝑣1, 𝑣2)
. The output is
𝑣2
,
and the next state of the FSM is 𝑣1.
The reduction relation only denes one-tick semantics.
The semantics of a system is dened by the trace of a given
input series 𝜌0, 𝜌1,· · · . We dene it formally below:
Denition 4.1 (Trace).The trace of a system
𝑡
with respect
to an input sequence
𝜌0, 𝜌1,· · ·
is the sequence
𝑜0, 𝑜1,· · ·
such that
𝑡𝜎0,𝜌0
𝑜0|𝜎1
. . .
𝑡𝜎𝑖,𝜌𝑖
𝑜𝑖|𝜎𝑖+1
. . .
In the above,
𝜎0
is the initial state of the implicit state
machines as specied in 𝑡.
4.3 Type System
To check well-formedness of programs, we introduce a sim-
ple type system to ensure that a well-typed program never
gets stuck. The type system is presented in Figure 5.
In the system, there are two types:
𝐵𝑜𝑜𝑙
for Boolean values
and
(𝑇1, . . . , 𝑇𝑛)
for tuples. We explain the typing rules below:
T-Bool. The type for Boolean values is always 𝐵𝑜𝑜𝑙 .
T-Input. For inputs, their types are predened in the
environment.
T-Var. For variables, their types also appear in the
environment.
Implicit State Machines LCTES ’22, June 14, 2022, San Diego, CA, USA
𝑣𝜎,𝜌
𝑣| (E-Value)𝑎𝜎,𝜌
𝜌(𝑎) | (E-Input)
𝑡1
𝜎,𝜌
𝑣1|𝜎[𝑥↦→ 𝑣1]𝑡2
𝜎,𝜌
𝑣2|𝜎′′
𝑙𝑒𝑡 𝑥 =𝑡1𝑖𝑛 𝑡2
𝜎,𝜌
𝑣|𝜎𝜎′′ (E-Let)
𝑡1
𝜎,𝜌
𝑣1|𝜎1. . . 𝑡𝑛
𝜎,𝜌
𝑣𝑛|𝜎𝑛
(𝑡1, . . . , 𝑡𝑛)𝜎 ,𝜌
(𝑣1, . . . , 𝑣𝑛) | 𝜎1 · · · 𝜎𝑛
(E-Tuple)
𝑡𝜎,𝜌
(𝑣1, . . . , 𝑣𝑖, . . . , 𝑣 𝑛) | 𝜎
𝑡.𝑖 𝜎,𝜌
𝑣𝑖|𝜎(E-Project)
𝑡1
𝜎,𝜌
𝛽1|𝜎𝑡2
𝜎,𝜌
𝛽2|𝜎′′ 𝛽=𝑎𝑛𝑑(𝛽1, 𝛽2)
𝑡1𝑡2
𝜎,𝜌
𝛽|𝜎𝜎′′ (E-And)
𝑡1
𝜎,𝜌
𝛽1|𝜎𝑡2
𝜎,𝜌
𝛽2|𝜎′′ 𝛽=𝑜𝑟 (𝛽1, 𝛽2)
𝑡1+𝑡2
𝜎,𝜌
𝛽|𝜎𝜎′′ (E-Or)
𝑡𝜎,𝜌
𝛽|𝜎𝛽=𝑛𝑜𝑡 (𝛽)
!𝑡𝜎,𝜌
𝛽|𝜎(E-Not)
𝑣=𝜎(𝑠) [𝑠↦→ 𝑣]𝑡|𝜎,𝜌
(𝑣1, 𝑣2) | 𝜎
fsm {𝑣0|𝑠𝑡}𝜎,𝜌
𝑣2| { 𝑠↦→ 𝑣1} 𝜎(E-Fsm)
Figure 4. Big-step operational semantics
𝑇::=𝐵𝑜𝑜𝑙 | (𝑇 , . . . , 𝑇 )
Γ𝛽:𝐵𝑜𝑜𝑙 (T-Bool)
𝑎:𝑇Γ
Γ𝑎:𝑇(T-Input)
𝑥:𝑇Γ
Γ𝑥:𝑇(T-Var)
Γ𝑡:𝐵𝑜𝑜𝑙
Γ!𝑡:𝐵𝑜𝑜𝑙 (T-Not)
Γ𝑡1:𝑇1. . . Γ𝑡𝑛:𝑇𝑛
Γ (𝑡1, . . . , 𝑡 𝑛):(𝑇1, . . . , 𝑇𝑛)(T-Tuple)
Γ𝑡:(𝑇1, . . . , 𝑇𝑖, . . . ,𝑇𝑛)
Γ𝑡.𝑖 :𝑇𝑖
(T-Project)
Γ𝑡1:𝐵𝑜𝑜𝑙 Γ𝑡2:𝐵𝑜𝑜𝑙
Γ𝑡1𝑡2:𝐵𝑜𝑜𝑙 (T-And)
Γ𝑡1:𝐵𝑜𝑜𝑙 Γ𝑡2:𝐵𝑜𝑜𝑙
Γ𝑡1+𝑡2:𝐵𝑜𝑜𝑙 (T-Or)
Γ𝑡1:𝑇1Γ, 𝑥:𝑇1𝑡2:𝑇2
Γ𝑙𝑒𝑡 𝑥 =𝑡1𝑖𝑛 𝑡2:𝑇2
(T-Let)
Γ𝑣:𝑇1Γ, 𝑠:𝑇1𝑡:(𝑇1,𝑇2)
Γfsm {𝑣|𝑠𝑡}:𝑇2
(T-Fsm)
Figure 5. Type System
LCTES ’22, June 14, 2022, San Diego, CA, USA Fengyun Liu and Aleksandar Prokopec
T-Not. The term 𝑡must be of the type 𝐵𝑜𝑜𝑙.
T-Tuple. If each component has a type, and then the
type of the tuple has a corresponding tuple type.
T-Project. If the term
𝑡
has a tuple type, then the pro-
jection has the type of the corresponding component.
T-And. If each component has the type
𝐵𝑜𝑜𝑙
, the result
also has the type 𝐵𝑜𝑜𝑙 .
T-Or. The same as above.
T-Let. If the bound term has the type of
𝑇1
, and the
body of the let-binding has the type
𝑇2
under the en-
vironment
Γ
extended with the binding
𝑥:𝑇1
, then the
let-binding has the type
𝑇2
. Note that this rule forbids
the usage of 𝑥in 𝑡1, which prevents undesired circles.
T-Fsm. If the initial value has the type
𝑇1
, and the body
has the type
(𝑇1,𝑇2)
under the environment
Γ
extended
with the binding
𝑠:𝑇1
, then the implicit state machine
has the type 𝑇2.
For the meta-theory of the type system, we need to dene
well-formedness of the input map and state map. We write
Γ𝜉
to mean that the input map or state map
𝜉
is well-typed
under Γ, which is dened as follows:
Γ Γ𝜉 𝑣:𝑇
Γ, 𝛼 :𝑇𝜉 { 𝛼↦→ 𝑣}
In the above,
𝛼
ranges over input and state variables, and
𝜉ranges over input map and state map.
Theorem 4.2 (Soundness).If
Γ𝑡
:
𝑇
, and if for each
𝜌𝑖
in
the input sequence
𝜌0, 𝜌1, . . .
we have
Γ𝜌𝑖
, then there exists
a trace for the system 𝑡corresponding to the input sequence.
The proof follows from the following lemma by induction
on the length of the input sequence:
Lemma 4.3. If
𝑡
is well-typed under the environment
Γ
, and
the input map
𝜌
is compatible with
Γ
, and the state map
𝜎
is
type-compatible with the initial state map
𝜎0
as specied in
𝑡
,
then 𝑡evaluates to a value 𝑣with updated state map 𝜎.
More formally, if
Γ𝑡
:
𝑇
, and
Γ𝜌
, and there exists
Γ
such that
Γ𝜎
and
Γ𝜎0
, then there exists
𝑣
and
𝜎
such
that 𝑡𝜎,𝜌
𝑣|𝜎,Γ𝑣:𝑇and Γ𝜎.
Sketch. By induction on the typing judgment Γ𝑡:𝑇.
4.4 Flattening
In this section, we show that any system of implicit state
machines is equivalent to a single at implicit state machine.
This can be achieved by a mechanic transformation.
For the purpose of the transformation, we rst dene the
combinational fragment of the language devoid of implicit
state machines, which is represented by 𝑒:
𝑒::=𝛽|𝑒𝑒|𝑒+𝑒|!𝑒| (𝑒, . . . ,𝑒) | 𝑒.𝑖 |
𝑙𝑒𝑡 𝑥 =𝑒 𝑖𝑛 𝑒 |𝑥|𝑠|𝑎
The combinational fragment corresponds to combinational
circuits, i.e., circuits without state elements, in contrast to
sequential circuits.
The transformation consists of two major steps:
Lifting: lifts FSMs to top-level (Figure 6).
Merging: merges FSMs to a single FSM (Figure 7).
Lifting (Figure 6) results in lifted normal form (u) where
all FSMs are nested at the top-level of the program, with a
combinational fragment in the middle:
𝑢::=𝑒|fsm {𝑣|𝑠𝑢}
The relation
𝑡1;𝐿𝑡2
says that the term
𝑡1
takes a lifting
step to
𝑡2
. Lifting is dened with the help of the lifting con-
text
𝐿
. The lifting context species that the transformation
follows the order left-right and top-down. The actual lifting
happens with the function
J·K
, which transforms the source
program to the expected form. We explain the concrete trans-
formation rules below:
fsm {𝑣|𝑠𝑒1} 𝑡2
. The FSM absorbs
𝑡2
into its
body. The symmetric case, and the cases for AND and
OR are similar.
𝑙𝑒𝑡 𝑥 =fsm {𝑣|𝑠𝑒1}𝑖𝑛 𝑡2
. It pulls the let-
binding into the body. The case in which FSM is in the
body of let-binding is similar.
fsm {𝑣|𝑠𝑒}.𝑖
. It pulls the projection into the
body of FSM.
(¯
𝑒, fsm {𝑣|𝑠𝑒},¯
𝑡)
. It pulls the tuple into the
body of FSM.
Note that to simplify the presentation, in the transforma-
tion rules we write
𝑙𝑒 𝑡 𝑥 , 𝑦 =𝑡1𝑖𝑛 𝑡2
as a syntactic sugar for
𝑙𝑒𝑡 𝑧 =𝑡1𝑖𝑛 𝑙𝑒𝑡 𝑥 =𝑧.1𝑖𝑛 𝑙𝑒𝑡 𝑦 =𝑧 .2𝑖𝑛 𝑡2.
Once all FSMs are nested at the top-level after lifting, merg-
ing (Figure 7) takes place. The relation
𝑢1;𝑀𝑢2
says that
the term
𝑢1
takes a merging step to
𝑢2
. Merging is dened
with the help of the merging context
𝑀
. The merging con-
text species that the merging happens from inside towards
outside. The actual merging step is quite straightforward: it
just combines the initial states
𝑣1
and
𝑣2
, as well as merges
𝑠1and 𝑠2into 𝑠.
4.5 Discussion
Flattening makes it immediately obvious that a digital cir-
cuit with state elements (such as registers and ip-ops) are
equivalent to a combinational circuit with all state elements
at the boundary.
Implicit State Machines LCTES ’22, June 14, 2022, San Diego, CA, USA
𝐿::=[·] | 𝐿𝑡|𝑒𝐿|𝐿+𝑡|𝑒+𝐿|!𝐿|𝐿.𝑖 | (𝑒1, . . . , 𝐿, . . . , 𝑡𝑛) |
fsm {𝑣|𝑠𝐿} | 𝑙 𝑒𝑡 𝑥 =𝐿 𝑖𝑛 𝑡 |𝑙𝑒𝑡 𝑥 =𝑒 𝑖𝑛 𝐿
J𝑡K=fsm {𝑣|𝑠𝑡}
𝐿[𝑡];𝐿𝐿[fsm {𝑣|𝑠𝑡}]
Jfsm {𝑣|𝑠𝑒1} 𝑡2K=fsm {𝑣|𝑠𝑙𝑒𝑡 𝑥 =𝑒1𝑖𝑛 (𝑥.1, 𝑥 .2𝑡2) }
J𝑒2fsm {𝑣|𝑠𝑒1}K=fsm {𝑣|𝑠𝑙𝑒𝑡 𝑥 =𝑒1𝑖𝑛 (𝑥.1, 𝑒2𝑥 .2) }
Jfsm {𝑣|𝑠𝑒1} + 𝑡2K=fsm {𝑣|𝑠𝑙𝑒𝑡 𝑥 =𝑒1𝑖𝑛 (𝑥.1, 𝑥 .2+𝑡2) }
J𝑒2+fsm {𝑣|𝑠𝑒1}K=fsm {𝑣|𝑠𝑙𝑒𝑡 𝑥 =𝑒1𝑖𝑛 (𝑥.1, 𝑒2+𝑥 .2) }
J!fsm {𝑣|𝑠𝑒}K=fsm {𝑣|𝑠𝑙𝑒𝑡 𝑥 =𝑒 𝑖𝑛 (𝑥 .1,!𝑥.2) }
J𝑙𝑒𝑡 𝑥 =fsm {𝑣|𝑠𝑒1}𝑖𝑛 𝑡2K=fsm {𝑣|𝑠𝑙𝑒𝑡 𝑠1, 𝑥 =𝑒1𝑖𝑛 (𝑠1, 𝑡2) }
J𝑙𝑒𝑡 𝑥 =𝑒1𝑖𝑛 fsm {𝑣|𝑠𝑒2}K=fsm {𝑣|𝑠𝑙𝑒𝑡 𝑥 =𝑒1𝑖𝑛 𝑒2}
Jfsm {𝑣|𝑠𝑒}.𝑖K=fsm {𝑣|𝑠𝑙𝑒𝑡 𝑥 =𝑒 𝑖𝑛 (𝑥 .1, 𝑥. 2.𝑖) }
J(¯
𝑒, fsm {𝑣|𝑠𝑒},¯
𝑡)K=fsm {𝑣|𝑠𝑙𝑒𝑡 𝑥 =𝑒 𝑖𝑛 (𝑥 .1,(¯
𝑒, 𝑥 .2,¯
𝑡)) }
Figure 6. Lifting of nested FSMs.
𝑀::=[·] | fsm {𝑣|𝑠𝑀}
J𝑢K=fsm {𝑣|𝑠𝑒}
𝑀[𝑢];𝑀𝑀[fsm {𝑣|𝑠𝑒}]
Jfsm {𝑣1|𝑠1fsm {𝑣2|𝑠2𝑒2} }K=fsm { (𝑣1, 𝑣 2) | 𝑠𝑙𝑒𝑡 𝑠1, 𝑠 2=𝑠 𝑖𝑛 𝑙𝑒𝑡 𝑥 =𝑒2𝑖𝑛 ( (𝑥 .2.1, 𝑥. 1), 𝑥.2.2) }
Figure 7. Merging of nested FSMs.
We believe the insight itself is not new, however, implicit
state machines make it obvious. In contrast, it is obscured
in the network-based model of digital circuits, e.g., it is not
obvious how to push a D ip-op in the middle of a circuit
network to its boundary.
The declarative nature of implicit state machines enables
the reasoning principle of substituting equals for equals [
33
].
It facilitates many common program optimizations, such as
dead-code elimination, common-subexpression elimination,
constant folding, etc.
[
35
] hold the view that it is a golden age for applying
programming language techniques for improving hardware
design. We believe implicit state machines may contribute
to that initiative.
5 Implicit State Machines in Scala
To assess the feasibility of implicit state machines as a pro-
gramming construct, we implemented an embedded DSL in
Scala for digital design. We experimented usability of the
embedded DSL by creating circuits of varying complexity,
from half adders to a micro-controller.
5.1 Embedded DSL
For readers not familiar with DSLs, there are generally two
approaches to implement a DSL:
External DSL, in which the DSL is implemented with
a standalone compiler (Figure 8)
Embedded DSL, in which the DSL is dened as a library
within a host language (Figure 9)
In the external approach, the language designer denes
syntax of the DSL, users write DSL programs and then feed
the source code into the DSL compiler. For practicality, there
is the need to provide IDE support for the DSL to improve
programming experience.
In the embedded approach, the language designer only
needs to dene the abstract syntax tree (AST) data format
and provide core compiler phases as a library in an imple-
mentation language, e.g., Scala. Users write DSL programs
in Scala to directly construct the ASTs, and then feed them
into the compilation pipeline. As programmers write code in
an existing language, e.g., Scala, there is no need to provide
additional IDE support.
Given that the embedded approach avoids the overhead
of dening concrete syntax of the DSL and providing IDE
suport, we follow the approach in our work.
Our DSL is based on implicit state machines extended with
pairs and bit vectors. Implicit state machines are the only
state elements in the DSL. An excerpt of the abstract syntax
tree denitions is presented in Figure 10.
LCTES ’22, June 14, 2022, San Diego, CA, USA Fengyun Liu and Aleksandar Prokopec
Check Optimization CodeGen Verilog
ASTAST
Parser
AST
source
Compiler
Figure 8. Architecture of External DSLs
Check Optimization CodeGen Verilog
ASTAST
DSLProgram
AST
Library
Application
Figure 9. Architecture of Embedded DSLs
1sealed abstract class Sig[T <: Type] // base class of AST
2case class Fsm[S <: Type, T <: Type](sym: Symbol, init: Value, body: Sig[S ~ T]) extends Sig[T]
3case class Let[S <: Type, T <: Type](sym: Symbol, sig: Sig[S], body: Sig[T]) extends Sig[T]
4case class Var[T <: Type](sym: Symbol, tpe: Type) extends Sig[T] // variable for inputs and bindings
5case class And[T <: Num](lhs: Sig[Vec[T]], rhs: Sig[Vec[T]]) extends Sig[Vec[T]]
6case class Mux[T <: Type](cond: Sig[Bit], thenp: Sig[T], elsep: Sig[T]) extends Sig[T]
7
8sealed abstract class Type // base class of types
9case class PairT[S <: Type, T <: Type](lhs: S, rhs: T) extends Type
10 case class VecT[T <: Num](width: T) extends Type
Figure 10. An excerpt of abstract syntax trees of the DSL
The class
Sig
is the base class of abstract syntax trees, and
the class
Type
is the base class of the types of signals. The
DSL also denes the following aliases for types:
1type ~[S <: Type, T <: Type] =PairT[S, T]
2type Vec[T <: Num] =VecT[T]
3type Bit =VecT[1]
4type Num =Int
The type
Sig[Bit]
denotes signals of 1-bit vector, which
is an alias of
Sig[Vec[1]]
. The type
Sig[Vec[2]]
denotes
signals of 2-bit vector. Here we take advantage of literal
types in Scala [
30
], which supports the usage of literal values
as types.
The DSL supports common bit-wise operations such as
XOR, AND, OR, ADD, SUB, SHIFT and MUX. All these op-
erations are supported in Verilog [
23
], and they follow the
same semantics as in Verilog.
The design intentionall makes the class
Sig
take an addi-
tional type parameter, which signies the type of the signal.
This way, we can prot the Scala type system to automat-
ically check signal mismatch errors, e.g., perform OR op-
eration on a 4-bit and an 8-bit signal. The additional type
parameter does not play any role at run-time.
5.2 A Quick Glance
The following code shows how we may implement a half
adder in our DSL:
1def halfAdder(a: Sig[Bit], b: Sig[Bit]) =
2val s=a^b
3val c=a&b
4c ++ s
The operator
++
concatenates two bit vectors to form a
bigger bit vector Sig[Vec[2]] in the example above.
We may compose two half adders to create a full adder,
which takes a carry cin as input:
1def full(a: Sig[Bit], b: Sig[Bit], cin: Sig[Bit]) =
2val ab =halfAdder(a, b)
3val s=halfAdder(ab(0), cin)
4val cout =ab(1) | s(1)
5cout ++ s(0)
In the above, we make two calls to
halfAdder
. Each call
will create a copy of the half adder circuit to be composed in
the fuller adder. It returns the carry and the sum. We may
compose them further to create a 2-bit adder:
1def adder2(a: Sig[Vec[2]], b: Sig[Vec[2]]) =
2val cs0 =full(a(0), b(0), 0)
3val cs1 =full(a(1), b(1), cs0(1))
4cs1(1) ++ cs1(0) ++ cs0(0)
Implicit State Machines LCTES ’22, June 14, 2022, San Diego, CA, USA
To actually generate a representation of the circuit, we
need to specify the input signals:
1val a=variable[Vec[2]]("a")
2val b=variable[Vec[2]]("b")
3val circuit =adder2(a, b)
Then we can create a simulator of the circuit:
1val add2 =circuit.eval(a, b)
Finally, we can test the simulator:
1add2(List(Value(1, 0), Value(0, 1))) match
2case Value(0, 1, 1) => println("success")
5.3 Sequential Circuits
We show how to create sequential circuits with the example
of moving average lter. The moving average lter we are
going to implement is specied below:
𝑌𝑖=(𝑋𝑖+2𝑋𝑖1+𝑋𝑖2)/4
For the input
𝑋𝑖
, the output
𝑌𝑖
also depends on the previous
values
𝑋𝑖1
and
𝑋𝑖2
. We can dene an operator
delay
based
on implicit state machines:
1def delay[T <: Type](sig: Sig[T], init: Value) =
2fsm("delay", init) { (last: Sig[T]) =>
3sig ~ last
4}
In the code above, we declare an implicit state machine
with the specied initial state
init
. The body of the FSM is a
pair
sig ~ last
, where the rst part becomes the next state,
and the second part becomes the output.
Now we may create the circuit for the moving average:
1def movingAverage(in: Sig[Vec[8]]) =
2val z1 =delay(in, 0.toValue(8))
3val z2 =delay(z1, 0.toValue(8))
4(in + (z1 << 1) + z2) >> 2
In the code above, we rst create an instance of the delay
circuit and bind it to the variable
z1
. Then we delay the
signal
z1
to get
z2
. Finally, the equation is encoded straight-
forwardly.
Note that in the above, the end user is programming in
dataow style à la Lustre [
11
]. There is no need for the
programmer to think in terms of state machines in such use
cases. We discuss this in a broader context in Section 5.6.
5.4 Verilog Generation
We can generate Verilog code for the moving average lter
as follows:
1val a=variable[Vec[8]]("a")
2val circuit =movingAverage(a)
3circuit.toVerilog("Filter", a)
The generated Verilog code is presented in Figure 11. In
the Verilog code, lines 9-14 deal with sequential logic, the
other code deal with combinational logic.
1module Filter (CLK, a, out);
2input CLK;
3input [7:0] a;
4output [7:0] out;
5reg [15:0] s;
6
7assign out =(s[7:0] + (s[15:8] << 1'b1) + a)
>> 2'b10;
8
9initial begin
10 s=16'b0000000000000000;
11 end
12
13 always @ (posedge CLK)
14 s <={ a, s[15:8] };
15 endmodule
Figure 11. Generated Verilog code for the moving average
lter (redundant parenthesese at line 8 manually removed
for the sake of readability)
Instr.
Memory
MODE
IO
ACC
MUX
Exec
(Pending)
PC Exec
(Normal)
Figure 12. Architecture of the micro-controller
This is the typical code generated by our DSL compiler,
as it performs attening of the circuit (Section 4.4), which
results in a single nite-state machine with a combinational
core.
The Verilog code generation takes a attened AST rep-
resentation of the circuit as input. It goes through the AST
representation and translate the DSL primitive with corre-
sponding Verilog code. As the translation process is standard,
we omit the details here.
5.5 Case Study: Micro-controller
We implemented an accumulator-based micro-controller in
the DSL inspired by Leros [31].
The architecture of the micro-controller is shown in Fig-
ure 12. At the high-level, the micro-controller contains three
architectural states: the program counter (PC), the accumu-
lator register (ACC) and the pending status (MODE). The
micro-controller interfaces with a memory bus, which con-
tains a simple protocol consisting of read address, control
(read / write) and data. The micro-controller contains an
LCTES ’22, June 14, 2022, San Diego, CA, USA Fengyun Liu and Aleksandar Prokopec
on-chip read-only instruction memory, which is dierent
from the external data memory interfaced by the bus.
The micro-controller is implemented with an implicit state
machine:
1fsm("processor", pc0 ~ acc0 ~ mode0) { state =>
2val pc ~ acc ~ mode =state
3// ...
4}
The variable
pc
refers to the program counter,
acc
is the
accumulator register,
mode
indicates whether the controller
is waiting for data from the external memory.
The skeleton of the implementation is as follows:
1let("pcNext", pc + 1) { pcNext =>
2let("instr", readInstr(pc)) { instr =>
3/* ... */
4when (opcode === ADDI.toSig(8)) {
5val acc2 =acc + operand
6next(acc =acc2)
7}
8/* ... */
9}
10 }
It rst increments the program counter
pc
and bind the
result to
pcNext
. Then it binds the current instruction to
instr
. At the circuit-level, the operations are executed in
parallel. Finally, the instruction is decoded and executed in
a series of
when
constructs, depending on the mode of the
micro-controller.
The
when
construct is a syntactic sugar created from multi-
plexers that supports selecting one of two n-bit inputs based
a 1-bit control signal.
Eventually, each branch calls the local method
next
with
appropriate arguments:
1def next(pc: Sig[PC] =pcNext,
2acc: Sig[ACC] =acc,
3mode: Sig[Bit] =0,
4out: Sig[BusOut] =0)
5=(pc ~ acc ~ mode) ~ out
As can be seen from above, the method
next
denes de-
fault values for all arguments, such that each branch may
only specify parameters that are dierent. For example, the
following code handles the unconditional jump instruction
BR:
1when (opcode === BR.toSig(8)) {
2next(pc =pc + jmpOffset)
3}
The indirect
ADD
instruction needs to load data from ex-
ternal memory, thus putting the controller in the pending
mode, as the following code shows:
1when (opcode === ADD.toSig(8)) {
2next(pc =pc, mode =1, out =readReq(instr))
3}
The logic for the pending mode is as follows:
1when (mode) {
2/* pending mode */
3when (opcode === ADD.toSig(8)) {
4next(acc =acc + busIn)
5}
6/* ... */
7} otherwise {
8/* normal mode */
9}
The code above depends on the protocol which requires
that the I/O devices make the requested data available on
the bus in the cycle following the request.
The programming experience is largely positive, thanks
to the declarative nature of the DSL. Compared to VHDL or
Verilog, there are no “wires” to connect in the DSL and there
are no combinational cyles by construction.
We test the implementation with small assembly programs
and verify the result with a circuit simulator in Scala. We
are aware that the micro-controller is still too simple and it
may not match quality standards. For example, we do not
implement pipelining [
25
] nor do we separate out a reusable
arithmetic-logic unit (ALU) for the two execution modes.
However, we conjecture that implicit state machines make
it possible to automate some of such optimizations using com-
pilation techniques. We leave it for future work to capitalize
on such insights to implement RISC-V cores and compare
with the state-of-the-art open source implementations.
5.6 Discussion: State Machine VS. Dataow
It has long been observed that embedded systems fall into
two categories: (1) control-dominated applications and (2)
data-oriented applications [
14
]. For control-dominated ap-
plications, programming based on nite-state machines is a
good t. For data-oriented applications, declarative dataow
programming is a good t. However, real systems are usu-
ally a mix of both styles, which motivates the extension of
the declarative dataow language Lustre [
11
] with state ma-
chines [
12
,
14
]. The extension is in imperative style with ex-
plicit state representation, and it desugars to a core dataow
calculus.
Our work can be seen as taken an opposite approach to
[
14
]: Instead of desugaring nite-state machines into a core
dataow calculus, we make implicit state machines as the fun-
damental building block, and desugar dataow programming
constructs to implicit state machines (Section 5.3). Given that
the dataow calculus of Lustre eventually compiles to nite-
state machines for execution, we believe the introduction of
implicit state machines as a primitive will be an interesting
addition to the programming methodologies of real-time and
embedded systems.
Implicit State Machines LCTES ’22, June 14, 2022, San Diego, CA, USA
5.7 Limitations
There are several limitations of the current DSL:
It does not support multi-clock design.
It only supports binary state, no analog nor tri-state.
It does not perform logic optimizations on the circuit.
While the DSL is useful to assess the practicality of implicit
state machines as a programing model, it is not a production-
ready artifact. Meanwhile, none of the limitations above
is an inherent drawback of implicit state machines as an
abstraction.
6 Related Work
We have discussed related work in Section 4.5 and Section 5.6.
Here we would like to acknowledge more work that inspired
our research.
Our work is inuenced by the french synchronous lan-
guages, Esterel [
7
], Signal [
6
] and Lustre [
11
]. In particular,
the semantics of implicit state machines follow the synchrony
hypothesis [
5
]. There are ongoing eorts in formalizing and
mechanizing the semantics of these languages [
10
,
16
] as
well as verifying programs in these languages [
34
], which
could be a direction for our future work.
There exists plenty of intermediate representations (IR)
for hardware design, such as Calyx [
28
], FIRRTL [
24
], LLHD
[
32
]. We believe implicit state machines will be a useful
abstraction in the design of IRs due to its declarativeness,
simplicity and universality.
Implicit state machines bear some similarity to state mon-
ads in functional programming [
36
]. From the programmer’s
perspective, there are three main dierences: (1) state mon-
ads require programmers to thread-through the state ex-
plicitly in the program, while there is no such requirement
for implicit state machines; (2) state monads do not allow
programmers to specify the initial state in a decentralized
way; (3) composing two state monads incurs overhead, while
compositionability is a feature of implicit state machines.
From the perspective of compiler writers, state monads are
just design patterns in functional programming, they are
categorically dierent from IRs that compiler phases can
work on.
There are many DSLs for digital design. The Lava fam-
ily DSLs [
8
,
17
] use delay as a primitive to represent state,
which can be thought as a restricted version of Lustre [
11
]
embedded in Haskell, i.e., they are in a dataow style as Lus-
tre. Chisel [
2
] uses registers as a state primitive and follows
an imperative programming style. Bluespec [
29
], Kami [
13
]
and Koika [
9
] are based on guarded atomic actions. Our DSL
is dierent in the sense that it is based on the novel state
primitive implicit state machines.
Graphical representation of programs seems to be favored
over text-based programs in some application domains. There
are several visual languages for programming with nite-
state machines, such as Statecharts [
21
], SyncCharts [
1
],
Simulink/Stateow [
19
]. We are investigating how to com-
bine the benets of visualizal languages and text-based lan-
guages in programming embedded systems.
7 Conclusion
In this paper, we showed that by sticking to the design prin-
ciple of declarativeness, we arrive at a novel abstraction:
implicit state machines. Implicit state machines are recur-
sively composable and universal, which makes them promis-
ing both as a programming model as well as intermediate
representation.
We formalized the concept of implicit state machines in
a calculus with Boolean algebra as the domain and showed
that it serves as an elegant model of digital circuits.
We implemented an embedded DSL in Scala based on im-
plicit state machines, which supports both dataow style
programming and state-machine style programming. We im-
plemented a micro-controller in the DSL and the experience
of programming with implicit state machines is positive.
Future Work. We are considering designing a standalone
domain-specic language based on implicit state machines
for the application domains of Internet of Things (IoT) and
industrial automation.
Acknowledgments
Fengyun Liu thanks the Programming Methods Laboratory
(LAMP) at École polytechnique fédérale de Lausanne (EPFL)
for hosting the research as part of his PhD studies. We also
thank Prof. Paolo Ienne, Prof. Viktor Kunčak, Prof. Martin
Odersky and Dr. Aggelos Biboudis for helpful discussions.
References
[1]
Charles André and Marie-Agnès Peraldi-Frati. 2000. Behavioral Speci-
cation of a Circuit Using SyncCharts: A Case Study. In 26th EUROMI-
CRO 2000 Conference, Informatics: Inventing the Future, 5-7 Septem-
ber 2000, Maastricht, The Netherlands. IEEE Computer Society, 1091.
hps://doi.org/10.1109/EURMIC.2000.874620
[2]
Jonathan Bachrach, Huy Vo, Brian C. Richards, Yunsup Lee, Andrew
Waterman, Rimas Avizienis, John Wawrzynek, and Krste Asanovic.
2012. Chisel: Constructing hardware in a Scala embedded language.
DAC Design Automation Conference 2012 (2012), 1212–1221.
[3]
Hendrik Pieter Barendregt. 1985. The lambda calculus - its syntax
and semantics. Studies in logic and the foundations of mathematics,
Vol. 103. North-Holland.
[4]
A. Benveniste and G. Berry. 1991. The synchronous approach to
reactive and real-time systems. Proc. IEEE 79, 9 (Sept. 1991). hps:
//doi.org/10.1109/5.97297
[5]
Albert Benveniste, Paul Caspi, Stephen A. Edwards, Nicolas Halb-
wachs, Paul Le Guernic, and Robert de Simone. 2003. The syn-
chronous languages 12 years later. Proc. IEEE 91, 1 (2003), 64–83.
hps://doi.org/10.1109/JPROC.2002.805826
[6]
Albert Benveniste, Paul Le Guernic, and Christian Jacquemot. 1991.
Synchronous programming with events and relations: the SIGNAL
language and its semantics. Science of Computer Programming 16, 2
(Sept. 1991). hps://doi.org/10.1016/0167-6423(91)90001- E
[7]
Gérard Berry and Georges Gonthier. 1992. The Esterel Synchronous
Programming Language: Design, Semantics, Implementation. Sci.
LCTES ’22, June 14, 2022, San Diego, CA, USA Fengyun Liu and Aleksandar Prokopec
Comput. Program. 19, 2 (1992), 87–152. hps://doi.org/10.1016/0167-
6423(92)90005-V
[8]
Per Bjesse, Koen Claessen, Mary Sheeran, and Satnam Singh. 1998.
Lava: Hardware Design in Haskell. In Proceedings of the third ACM SIG-
PLAN International Conference on Functional Programming (ICFP ’98),
Baltimore, Maryland, USA, September 27-29, 1998, Matthias Felleisen,
Paul Hudak, and Christian Queinnec (Eds.). ACM, 174–184. hps:
//doi.org/10.1145/289423.289440
[9]
Thomas Bourgeat, Clément Pit-Claudel, Adam Chlipala, and Arvind.
2020. The essence of Bluespec: a core language for rule-based hardware
design. In Proceedings of the 41st ACM SIGPLAN International Confer-
ence on Programming Language Design and Implementation, PLDI 2020,
London, UK, June 15-20, 2020, Alastair F. Donaldson and Emina Torlak
(Eds.). ACM, 243–257. hps://doi.org/10.1145/3385412.3385965
[10]
Timothy Bourke, Lélio Brun, Pierre-Évariste Dagand, Xavier Leroy,
Marc Pouzet, and Lionel Rieg. 2017. A Formally Veried Compiler for
Lustre. (2017).
[11]
P. Caspi, D. Pilaud, N. Halbwachs, and J. A. Plaice. 1987. LUSTRE: A
Declarative Language for Real-time Programming. In Proceedings of the
14th ACM SIGACT-SIGPLAN Symposium on Principles of Programming
Languages (POPL ’87). ACM, New York, NY, USA. hps://doi.org/10.
1145/41625.41641 event-place: Munich, West Germany.
[12]
Paul Caspi and Marc Pouzet. 2008. Synchronous Functional Program-
ming : The Lucid Synchrone Experiment.
[13]
Joonwon Choi, Muralidaran Vijayaraghavan, Benjamin Sherman,
Adam Chlipala, and Arvind. 2017. Kami: a platform for high-level
parametric hardware specication and its modular verication. Proc.
ACM Program. Lang. 1, ICFP (2017), 24:1–24:30. hps://doi.org/10.
1145/3110268
[14]
Jean-Louis Colaço, Bruno Pagano, and Marc Pouzet. 2005. A con-
servative extension of synchronous data-ow with state machines.
In Proceedings of the 5th ACM international conference on Embedded
software - EMSOFT ’05. ACM Press, Jersey City, NJ, USA. hps:
//doi.org/10.1145/1086228.1086261
[15]
Mary F. Fernández, Daniela Florescu, Alon Y. Halevy, and Dan Suciu.
2000. Declarative specication of Web sites with Strudel. The VLDB
Journal 9 (2000), 38–55.
[16]
Spencer P. Florence, Shu-Hung You, Jesse A. Tov, and Robert Bruce
Findler. 2019. A calculus for Esterel: if can, can. if no can, no can.
Proceedings of the ACM on Programming Languages 3, POPL (Jan. 2019).
hps://doi.org/10.1145/3290374
[17]
Andy Gill, Tristan Bull, Garrin Kimmell, Erik Perrins, Ed Komp, and
Brett Werling. 2009. Introducing Kansas Lava. In Implementation and
Application of Functional Languages - 21st International Symposium,
IFL 2009, South Orange, NJ, USA, September 23-25, 2009, Revised Selected
Papers (Lecture Notes in Computer Science, Vol. 6041), Marco T. Morazán
and Sven-Bodo Scholz (Eds.). Springer, 18–35. hps://doi.org/10.1007/
978-3- 642-16478- 1_2
[18]
Nicolas Halbwachs, Daniel Pilaud, Farid Ouabdesselam, and Anne-
Cecile Glory. 1989. Specifying, Programming and Verifying Real-
Time Systems Using a Synchronous Declarative Language. In Auto-
matic Verication Methods for Finite State Systems, International Work-
shop, Grenoble, France, June 12-14, 1989, Proceedings (Lecture Notes in
Computer Science, Vol. 407), Joseph Sifakis (Ed.). Springer, 213–231.
hps://doi.org/10.1007/3-540- 52148-8_18
[19]
Grégoire Hamon and John M. Rushby. 2007. An operational semantics
for Stateow. Int. J. Softw. Tools Technol. Transf. 9, 5-6 (2007), 447–456.
hps://doi.org/10.1007/s10009-007- 0049-7
[20]
Michael Hanus and Christof Kluß. 2009. Declarative Programming of
User Interfaces. In PADL.
[21]
David Harel. 1987. Statecharts: a visual formalism for complex systems.
Science of Computer Programming 8, 3 (June 1987). hps://doi.org/10.
1016/0167-6423(87)90035- 9
[22]
Timothy L. Hinrichs. 2011. Plato: A Compiler for Interactive Web
Forms. In PADL.
[23]
IEEE. 2005. IEEE Standard for Verilog Hardware Description Language.
IEEE.
[24]
Adam M. Izraelevitz, Jack Koenig, Patrick Li, Richard Lin, Angie Wang,
Albert Magyar, Donggyu Kim, Colin Schmidt, Chick Markley, Jim
Lawson, and Jonathan Bachrach. 2017. Reusability is FIRRTL ground:
Hardware construction languages, compiler frameworks, and trans-
formations. In 2017 IEEE/ACM International Conference on Computer-
Aided Design, ICCAD 2017, Irvine, CA, USA, November 13-16, 2017, Sri
Parameswaran (Ed.). IEEE, 209–216. hps://doi.org/10.1109/ICCAD.
2017.8203780
[25]
Daniel Kroening and Wolfgang J. Paul. 2001. Automated Pipeline
Design. In Proceedings of the 38th Design Automation Conference, DAC
2001, Las Vegas, NV, USA, June 18-22, 2001. ACM, 810–815. hps:
//doi.org/10.1145/378239.379071
[26]
Michael Leuschel. 2008. Declarative programming for verication:
lessons and outlook. In PPDP ’08.
[27]
Xun Li, Mohit Tiwari, Jason Oberg, Vineeth Kashyap, Frederic T.
Chong, Timothy Sherwood, and Ben Hardekopf. 2011. Caisson: a
hardware description language for secure information ow. In Pro-
ceedings of the 32nd ACM SIGPLAN Conference on Programming Lan-
guage Design and Implementation, PLDI 2011, San Jose, CA, USA, June
4-8, 2011, Mary W. Hall and David A. Padua (Eds.). ACM, 109–120.
hps://doi.org/10.1145/1993498.1993512
[28]
Rachit Nigam, Samuel Thomas, Zhijing Li, and Adrian Sampson. 2021.
A compiler infrastructure for accelerator generators. In ASPLOS ’21:
26th ACM International Conference on Architectural Support for Pro-
gramming Languages and Operating Systems, Virtual Event, USA, April
19-23, 2021, Tim Sherwood, Emery D. Berger, and Christos Kozyrakis
(Eds.). ACM, 804–817. hps://doi.org/10.1145/3445814.3446712
[29]
Rishiyur S. Nikhil. 2004. Bluespec System Verilog: ecient, correct
RTL from high level specications. In 2nd ACM & IEEE International
Conference on Formal Methods and Models for Co-Design (MEMOCODE
2004), 23-25 June 2004, San Diego, California, USA, Proceedings. IEEE
Computer Society, 69–70. hps://doi.org/10.1109/MEMCOD.2004.
1459818
[30]
Martin Odersky. 2019. Scala Language Specication. hps://scala-
lang.org/files/archive/spec/2.13/.
[31] Martin Schoeberl. 2011. Leros: A Tiny Microcontroller for FPGAs. In
International Conference on Field Programmable Logic and Applications,
FPL 2011, September 5-7, Chania, Crete, Greece. IEEE Computer Society,
10–14. hps://doi.org/10.1109/FPL.2011.13
[32]
Fabian Schuiki, Andreas Kurth, Tobias Grosser, and Luca Benini. 2020.
LLHD: a multi-level intermediate representation for hardware descrip-
tion languages. In Proceedings of the 41st ACM SIGPLAN International
Conference on Programming Language Design and Implementation, PLDI
2020, London, UK, June 15-20, 2020, Alastair F. Donaldson and Emina
Torlak (Eds.). ACM, 258–271. hps://doi.org/10.1145/3385412.3386024
[33]
Harald Søndergaard and Peter Sestoft. 1990. Referential transparency,
deniteness and unfoldability. Acta Informatica 27 (1990), 505–517.
[34]
Yahui Song and Wei-Ngan Chin. 2021. A Synchronous Eects Logic for
Temporal Verication of Pure Esterel. In Verication, Model Checking,
and Abstract Interpretation - 22nd International Conference, VMCAI
2021, Copenhagen, Denmark, January 17-19, 2021, Proceedings (Lecture
Notes in Computer Science, Vol. 12597), Fritz Henglein, Sharon Shoham,
and Yakir Vizel (Eds.). Springer, 417–440. hps://doi.org/10.1007/978-
3-030- 67067-2_19
[35]
Lenny Truong and Pat Hanrahan. 2019. A Golden Age of Hardware
Description Languages: Applying Programming Language Techniques
to Improve Design Productivity. In 3rd Summit on Advances in Pro-
gramming Languages, SNAPL 2019, May 16-17, 2019, Providence, RI,
USA (LIPIcs, Vol. 136), Benjamin S. Lerner, Rastislav Bodík, and Shri-
ram Krishnamurthi (Eds.). Schloss Dagstuhl - Leibniz-Zentrum für
Informatik, 7:1–7:21. hps://doi.org/10.4230/LIPIcs.SNAPL.2019.7
Implicit State Machines LCTES ’22, June 14, 2022, San Diego, CA, USA
[36]
Philip Wadler. 1992. Monads for functional programming. In Program
Design Calculi, Proceedings of the NATO Advanced Study Institute on
Program Design Calculi, Marktoberdorf, Germany, July 28 - August 9,
1992 (NATO ASI Series, Vol. 118), Manfred Broy (Ed.). Springer, 233–264.
hps://doi.org/10.1007/978-3- 662-02880- 3_8
ResearchGate has not been able to resolve any citations for this publication.
Chapter
Full-text available
Esterel is an imperative synchronous language that has found success in many safety-critical applications. Its precise semantics makes it natural for programming and reasoning. Existing techniques tackle either one of its main challenges: correctness checking or temporal verification. To resolve the issues simultaneously, we propose a new solution via a Hoare-style forward verifier and a term rewriting system (TRS) on Synced Effects. The first contribution is, by deploying a novel effects logic, the verifier computes the deterministic program behaviour via construction rules at the source level, defining program evaluation syntactically. As a second contribution, by avoiding the complex translation from LTL formulas to Esterel programs, our purely algebraic TRS efficiently checks temporal properties described by expressive Synced Effects. To demonstrate our method’s feasibility, we prototype this logic; prove its correctness; provide experimental results, and a number of case studies.
Article
Full-text available
The language Esterel has found success in many safety-critical applications, such as fly-by-wire systems and nuclear power plant control software. Its imperative style is natural to programmers building such systems and its precise semantics makes it work well for reasoning about programs. Existing semantics of Esterel generally fall into two categories: translation to Boolean circuits, or operational semantics that give a procedure for running a whole program. In contrast, equational theories enable reasoning about program behavior via equational rewrites at the source level. Such theories form the basis for proofs of transformations inside compilers or for program refactorings, and defining program evaluation syntactically. This paper presents the first such equational calculus for Esterel. It also illustrates the calculus’s usefulness with a series of example equivalences and discuss how it enabled us to find bugs in Esterel implementations.
Conference Paper
Full-text available
The correct compilation of block diagram languages like Lustre, Scade, and a discrete subset of Simulink is important since they are used to program critical embedded control software. We describe the specification and verification in an Interactive Theorem Prover of a compilation chain that treats the key aspects of Lustre: sampling, nodes, and delays. Building on CompCert, we show that repeated execution of the generated assembly code faithfully implements the dataflow semantics of source programs. We resolve two key technical challenges. The first is the change from a synchronous dataflow semantics, where programs manipulate streams of values, to an imperative one, where computations manipulate memory sequentially. The second is the verified compilation of an imperative language with encapsulated state to C code where the state is realized by nested records. We also treat a standard control optimization that eliminates unnecessary conditional statements.
Article
It has become fairly standard in the programming-languages research world to verify functional programs in proof assistants using induction, algebraic simplification, and rewriting. In this paper, we introduce Kami, a Coq library that enables similar expressive and modular reasoning for hardware designs expressed in the style of the Bluespec language. We can specify, implement, and verify realistic designs entirely within Coq, ending with automatic extraction into a pipeline that bottoms out in FPGAs. Our methodology, using labeled transition systems, has been evaluated in a case study verifying an infinite family of multicore systems, with cache-coherent shared memory and pipelined cores implementing (the base integer subset of) the RISC-V instruction set.
Article
We present a broad extension of the conventional formalism of state machines and state diagrams, that is relevant to the specification and design of complex discrete-event systems, such as multi-computer real-time systems, communication protocols and digital control units. Our diagrams, which we call statecharts, extend conventional state-transition diagrams with essentially three olements, dealing, respectively, with the notions of hierarchy, concurrency and communication. These transform the language of state diagrams into a highly structured&apos; and economical description language. Statecharts are thus compact and expressive--small diagrams can express complex behavior--as well as compositional and modular. When coupled with the capabilities of computerized graphics, statecharts enable viewing the description at different levels of detail, and make even very large specifications manageable and comprehensible. In fact, we intend to demonstrate here that statecharts counter many of the objections raised against conventional state diagrams, and thus appear to render specification by diagrams an attractive and plausible approach. Statecharts can be used either as a stand-alone behavioral description or as part of a more general design methodology that deals also with the system&apos;s other aspects, such as functional decomposition and data-flow specification. We also discuss some practical experience that was gained over the last three years in applying the statechart formalism to the specification of a particularly complex system.