LCM ConceptThe information in this section will help you understand LCM concepts. Reactive MachinesLCM belongs to the family of languages dedicated to describe the
behavior of reactive machines, i.e. machines which react to inputs
given by an external environment. This behavior is cyclic and each
cycle consists in three stages:
![]() Reactive machines do not usually collect inputs during computation. The system can therefore act as a state machine whose transitions are triggered by the inputs and whose stable states are the states of the machine during waiting times. In the manufacturing industry, these state machines have most of the time a finite number of states and programmers expect their machine to have a deterministic behavior: given a state, the same inputs always produce the same outputs. They are called deterministic Finite State Machine (deterministic FSM). LCM is a Synchronous LanguageLCM obeys the synchronous hypothesis. This means that each reactive cycle is atomic, i.e. the computing stage of the reactive cycle cannot be cut into smaller pieces. Moreover, the system behaves as if its atomic cycle was computed in zero time. In other words, the outputs are logically emitted in the same instant as the inputs. The consequence is that the behavior of a synchronous system for a given cycle is determined only by the state of this system at the previous cycle and by the value of its inputs. LCM is Based on a Formal LanguageLCM is a based on a formal language, i.e. the semantics of LCM can be described as a set of mathematical equations that are independent of the implementation. What does this mean for the user? As a developer of an LCM program, you want to clearly understand the behavior of your program. You don't have to understand how the LCM is implemented and simulated, but the LCM principles that are exposed herein. Sharing Information Between Parallel ProcessesIn common languages used in control programming, communication
between parallel processes raises well known problems. Writing
value in one process and reading it in a parallel process may lead
to behaviors uncontrolled by the user. The typical example usually
used to demonstrate this issue is the following:
The graph above represents a 3-step sequence (3 cycles): the element x has the value "0" at first step. The following step, two processes run in parallel. They affect respectively the value "1" to the variable x and the value of x to the element a. What is the result of this program? Will it print b=1 or b=0? This is precisely when the confusion comes from: when using variables to share information (data) in between two parallel processes. And this is exactly the kind of confusion that LCM solves, using signals for every data communication between parallel branches. For a given cycle, writing signals values is done before reading signals values. This rule solves synchronization problems between parallel branches and ensures unique signal value warranty. SignalsSFC Editor The signal is the fundamental notion of LCM. Using signals is the only way to communicate data in between parallel processes: it is synchronously broadcasted. A signal is an element that has a status (present or absent) and carries a value. A pure signal (i.e. simple) has a status only, while a valuated signal has a status and carries a value. A signal "S" is present only if it is emitted during the reaction cycle, by executing the action "S <- x" which gives the value x to S. It cannot be explicitly reset (this shows the main difference between a signal and a variable). Therefore, it is absent only if it has not been emitted during the reaction cycle. The status of a signal is always coherent, that is: the status of a signal remains the same during one entire cycle. A signal can be either present for each test performed in the same cycle, or absent for each test performed in the same cycle. The value of a valuated signal is set by emitting the signal, which means the value of a valuated signal remains the same for each evaluation in the same cycle. If a valuated signal is not emitted, its value from the previous cycle is kept. The status of the signal is given by the "?" Boolean operator which returns true if "S" is present, and false if "S" is absent. The value of a signal has always a type. (see Predefined Types and Functions) The LCM Compiler Synchronizes Parallel Computation: Communication Between Parallel Branches is SafeAnother important concept of LCM is the parallel construct. The parallel construct allows safe parallel composition of several FSM (Finite State Machine). The parallel construct can be terminated only and only when all parallel branches are terminated. The parallel construct is symmetric, i.e. the behavior is exactly the same if the user changes the order of the parallel branches. Communication between parallel branches is safe because only signals can be shared between parallel branches. The LCM compiler synchronizes signal emissions and tests that all values needed for calculation are written before they are read. Therefore, the example shown in Sharing Information Between Parallel Processes, when computed by the LCM compiler, will clearly print out the right value for b. The LCM compiler organizes the calculation of the two parallel branches like this: the value of x is needed to assign the value of a, so its value is set first. Then x is assigned to a. So clearly the value of b will be 1. Properties of an LCM Program
LCM Program ExecutionHow are atomic cycles determined? Bounds of atomic cycles are set by reaching a pause in control paths. Here is how it works: for each cycle and in all parallel branches, instructions are executed until a pause is reached. These pauses are set active, the next cycle the program execution continues starting from all active pauses. The state of a program is the union of the set of active pauses and the value of each signal. CompilerThe information in this section will help you understand the LCM compiler. SignatureAll LCM elements have a signature. Signatures are calculated by the compiler for type checking purpose. Keywords used in a signature are module for a module signature, type for types and val for values: constants, functions, ports, expressions.
Type InferenceSpecifying a type when defining modules values (that is, constants, functions and blocks) puts a type constraint. A type constraint also exists when an element is used in an expression. However, setting those types explicitly is not mandatory, because the LCM compiler guesses element types by an inference mechanism:
For example, if a process performs the following operation on non-typed elements: if v = w then x receive the value of y The result of the type checker will be: v: any1 w: any1 x: any2 y: any2 The type checker has unified under the same type the values v and w (because of the equality test made in the if statement) and x and y (because of the assignment instruction in the then statement). Nothing links the variables any1 and any2 a priori. PolymorphismSFC Editor From the example above any1 and any2 are type variables of a polymorphic type. As every value has always a type, the LCM compiler automatically associates a type variable to all values defined without type constraint. Polymorphic types are above all other types in the sense that they are the most general type. Having a value with 'any as a type is having full polymorphism on that value. From the previous example, both types any1 and any2 can be replaced by any other type when the operation is called. As said in the previous section, LCM provides several families of types gathered in type classes. Types from the same class share several common operators and functions (see their definition in the next section), and different numeric types (gathered under the class Number) share several arithmetic operators. As a consequence, you can define a polymorphic block which instance will, if instantiated in a specific context, expose a signature being a subset of the reference's signature. A "subset" because order relations on signatures are determined by applicative definitions of type classes (i.e. the Pervasives library). Direction InferenceSFC Editor Giving a direction constraint to a port is not mandatory. The LCM compiler infers directions based on the following considerations, made on the analysis of instructions performed on a signal. If the signal is:
About Causality ErrorsIn LCM, it is forbidden to write programs involving causality loops. A program has a causality loop if the constructiveness rule is transgressed. Causality loops are detected at compile time: the LCM compiler rejects programs in which signals writes cannot be statically scheduled before signals reads. From the user's view, it is easy to understand why this rule is violated, because the compiler isolates and indicates unconstructive (non-schedulable) LCM code parts. In other words, the LCM compiler displays a list of actions and transitions involved in the causality loop.
|