Author: Tamim Nassar
Last updated: 1/5/2005
Translation from SAL to CDL is not trivial. When attempting to translate models from SAL to CDL we may face many problems that need special techniques to solve. This document will show these problems and how we can solve them,
Although most translation problems can be solved, there are some that are too difficult to solve. Here is a list of translation constraints that the translator must enforce:
Array [1..N] OF INTEGER is allowed
if N a constant.Array [x:INTEGER | x<N] is not
allowed.The non-combinational SAL module looks like this:
name: MODULE = BEGIN INPUT/OUTPUT/GLOBAL/LOCAL (variable declarations) DEFINITION (definitions) INITIALIZATION (initialization) TRANSITION (transitions) END; |
When translating the module to the Core representation, we have to know how each part will be represented. Although definitions and transitions are trivial, the variable definitions and the initializations are not as trivial.
The core representation should look like this
Module name(input,output and global variables){
VAR local variables (initialized)
DEFINE definitions
TRANS transitions
}
|
The translation of each one of these parts will be shown below.
Combinational SAL module translation is trivial. Here's an example:
| Sal | Core |
system: MODULE = (USER || USER); |
MODULE system() {
(( USER() || USER() ))
}
|
Variable declaration is intuitive.
| Sal | Core |
Q: MODULE =
BEGIN
INPUT in : INTEGER
OUTPUT out : INTEGER
LOCAL arr : ARRAY NATURAL OF Data
GLOBAL glob : NATURAL
END;
|
MODULE Q(in:INTEGER, out:INTEGER, glob:INTEGER){
VAR arr: ARRAY [MAX_SIZE] of Data
}
|
Definitions translation is intuitive.
| Sal | Core |
DEFINITION
first = contents[head]
|
DEFINE first := contents[head]; |
When a local variable is initialized, the translation should have INITVAL set in the variable definition. However, when an input variable or a global variable is initialized, an initialization transformation must be added to the module.
| Sal | Core |
clock: MODULE =
BEGIN
INPUT time_out: TIMEOUT_ARRAY
OUTPUT time: TIME
INITIALIZATION
time = 0
TRANSITION
[ time_elapses:
time < time_out -->
time' = time_out ]
END;
|
MODULE clock(
time_out: ARRAY [ MAX_SIZE ] OF TIME ,
time : TIME )
{
VAR
inited: boolean INITVAL false ;
Trans T#init:
enable: inited := false;
assign: inited := true ; time := 0 ;
Trans T#3:
enable: inited /\ ( time < time_out ) ;
assign: time ' := time_out ;
}
|
| Sal | Core |
process: MODULE =
BEGIN
INPUT time: TIME
GLOBAL lock: LOCK_VALUE
OUTPUT timeout: TIME
LOCAL pc: PC
INITIALIZATION
pc = sleeping;
timeout IN { x: TIME | time < x };
lock = 0
TRANSITION
[ waking_up:
pc = sleeping AND
time = timeout AND lock = 0
--> pc' = waiting;
timeout' IN { x: TIME |
time < x AND x <= time + delta1 }
[] try_again_later:
pc = sleeping AND time = timeout AND lock /= 0
-->
timeout' IN { x: TIME | time < x }
]
END;
|
MODULE process(
time: TIME,
lock: LOCK_VALUE,
timeout: TIME)
{
VAR
pc: PC INITVAL sleeping;
inited: boolean INITVAL false;
x: TIME;
Trans T#init:
enable: inited := false;
assign: inited:= true; lock: = 0;
relation: (timeout' = x) /\ (time < x);
Trans T#2:
enable: inited /\ (((pc = sleeping) /\
(time = timeout)) /\ (lock = 0));
assign: pc':= waiting;
relation: (timeout' = x) /\ ((time < x) /\
(x < = (time+delta1)));
Trans T#3:
enable: inited /\ (((pc = sleeping) /\
(time = timeout)) /\ (lock! = 0));
relation: (timeout' = x) /\ (time < x);
}
|
| Sal | Core |
Queue: TYPE = [# data: INTEGER,
tl: BOOLEAN #];
|
TYPE T#Queue#data: INTEGER; T#Queue#tl: BOOLEAN; |
There are two types of transitions:
The first type of transitions is easy to translate:
| Sal | Core |
ENTERING_AND_SEMAPHOR_IS_FALSE:(label of trans.)
(user_state = entering)
AND (semaphore = false) -->
user_state' = critical;
semaphore' = true
|
Trans T#2: (some label)
enable: ( user_state = entering )
/\ ( semaphore = false );
assign: user_state':= critical;
semaphore' := true;
|
The second type is not as trivial as we can see in the following example
| Sal | Core |
TRANSITION head' = a tail' = b |
Trans T#2: (some label) enable: true; relation: (head'=a)/\(tail'=b) |
The reason we used the relation here is to make a common ground for the conditions and the assignments as we will next see:
There is no need to split the transition into several transitions each with a unique enable condition. We can translate the transition by creating a logical combination of all the assignments in the conditions. This technique will work also for conditions inside conditions.
| Sal | Core |
TRANSITION
head' =
IF op = pop THEN head+1 ELSE head ENDIF;
tail' =
IF op = push THEN tail+1 ELSE tail ENDIF
|
Trans T#2: (some label)
enable: true;
relation:
(((op=pop) /\ (head'=(head+1))
\/ (!(op=pop) /\ (head'=head)))
/\
(((op=push) /\ (tail'=(tail+1))
\/ (!(op=push) /\ (tail'=tail)))
|
Note that an other possible translation for conditional expressions is where each condition is put into a separate transformation. However, to implement this translation we have to check all the conditions and if there are conditions that are equivalent then they should be in the same transition. Also, if there are two conditions, then we need to generate four transitions to cover all the possibilities, and if we have three conditions then we will need to create 8 transitions. Therefore, this translation option is very problematic.
Some non-deterministic assignment problems are trivial:
| Sal | Core |
TRANSITION
NON_DETERMINISTIC_IDLE_OR_ENTERING:
user_state = idle -->
user_state' IN {idle, entering}
|
Trans T#2: (some label)
enable: user_state = idle ;
assign: user_state' := {entering, idle};
|
Other non-deterministic assgnment problems are more complicated. The solution is adding relations.
| Sal | Core |
process: MODULE =
BEGIN
INPUT time: TIME
GLOBAL lock: LOCK_VALUE
OUTPUT timeout: TIME
LOCAL pc: PC
INITIALIZATION
pc = sleeping;
timeout IN { x: TIME | time < x };
lock = 0
TRANSITION
[ waking_up:
pc = sleeping AND
time = timeout AND lock = 0 -->
pc' = waiting;
timeout' IN { x: TIME |
time < x AND x <= time + delta1 }
[] try_again_later:
pc = sleeping AND
time = timeout AND lock /= 0 -->
timeout' IN { x: TIME | time < x }
]
END;
|
MODULE process(
time: TIME,
lock: LOCK_VALUE,
timeout: TIME){
VAR
pc: PC INITVAL sleeping;
inited: boolean INITVAL false;
x: TIME;
Trans T#init:
enable: inited := false;
assign: inited:= true; lock: = 0;
relation: (timeout' = x) /\ (time < x);
Trans T#2:
enable: inited /\ (((pc = sleeping) /\
(time = timeout)) /\ (lock = 0));
assign: pc':= waiting;
relation: (timeout' = x) /\ ((time < x) /\
(x < = (time+delta1)));
Trans T#3:
enable: inited /\ (((pc = sleeping) /\
(time = timeout)) /\ (lock! = 0));
relation: (timeout' = x) /\ (time < x);
}
|