Les dejo la siguiente aportación de como definir una máquina de estados finita en WinCUPL
si no quieres copiar el código, les dejo un archivo de txt que lo incluye
Máquinas de estado con WincuPL
Empezamos por definir los estados con #DEFINE
$DEFINE S0 'b'000 // En este caso llamamos a este estado SO para no tener que estar
/* escribiendo su representacion binaria 000 en este caso */
$DEFINE S1 'b'110 // nota que no necesariamente sigue un orden binario
// ya que #DEFINE solo le dice a Winucpl que sustituya S1 por 110
Una vez definidos los estados, definimos la máquina de estados finita(FSM).
Para ello utilizamos la siguiente estructura
SEQUENCE nombre
{
La definición completa de la máquina de estado esta comprendido entre estos curly braces
}
Para declarar los estados usamos la palabra PRESENT, debe haber un PRESENT por cada estado
que deseamos
PRESENT S0 /* Define estado S0 */
PRESENT S1 /* Define estado S1 */
Ahora viene lo interesante:
ya que dependiendo del tipo de máquina que deseamos (Syncronica ó asincrónica)
usamos diferentes definiciones de las transiciones.
/* TABLA 1. Transiciones posibles en CUPL .
Statement Description
IF NEXT Transición condicional al siguiente estado
IF NEXT OUT Transición condicional al siguiente estado con salida Sincrónica
NEXT Transición Incondicional al siguiente estado
NEXT OUT Transición Incondicional al siguiente estado con salida Asincrónica
OUT salida asyncronica Incondicional
IF OUT salida asincrónica condicional
usamos DEFAULT después de un IF como sustituto de ELSE
DEFAULT NEXT Transición condicional al siguiente estado si el IF no se cumplió
DEFAULT OUT Transición condicional al siguiente estado con salida Asyncronica
DEFAULT NEXT OUT Transición condicional al siguiente estado con salida sincrónica
*/
Un ejemplo aclara un poco
/* Uso Field para agrupar salidas o entradas a una palabra en este caso estados*/
/* me agrupa las salidas Q3,Q2,Q1,Q0 */
FIELD estados = [Q3, Q2, Q1, Q0] ;
/* Defino los estados por comodidad sigo el binario */
$DEFINE S0 'b' 0000 /* Rojo - - - */
$DEFINE S1 'b' 0001 /* Rojo Naranja - - */
$DEFINE S2 'b' 0010 /* - Naranja - - */
$DEFINE S3 'b' 0011 /* - Naranja Verde - */
$DEFINE S4 'b' 0100 /* - - Verde - */
$DEFINE S5 'b' 0101 /* - Naranja Verde - Ahora en reversa */
$DEFINE S6 'b' 0110 /* - Naranja - - Ahora en reversa*/
$DEFINE S7 'b' 0111 /* Rojo Naranja - - Ahora en reversa */
$DEFINE S8 'b' 1000 /* Rojo - - Cuenta Ahora en reversa */
/* y defino la máquina de estados por medio de las transiciones entre estados
/* máquina Asyncronica no entradas solo el reloj el cúal cambia los estados
// Nota: Solo el GAL22V10 tiene Reset asincrónico (.AR), la 16V8 o la 20v8 solo
// puede ser usada con Reset Sincrónico.
Nota: aunque no esta documentado, se puede usar // para hacer un comentario de linea
como lo hace c++.
También aunque no esta documentado, WinCUPL no acepta acentos o guiones, ni
siquiera en los comentarios */
SEQUENCE estados
{
PRESENT S0
OUT Rojo ; // Forzo la Salida Rojo mientras este en el estado
IF Rst NEXT S1; // Entrada Rst= 1 lleva la transición al estado S1
DEFAULT NEXT S0 ; // Entrada Rst = 0 me mantiene en el mismo estado
PRESENT S1
OUT Rojo, Naranja ; // Dos salidas, se tienen que separar con una coma
IF Rst NEXT S2; // Entrada Rst= 1 lleva la transición al estado S1
DEFAULT NEXT S0 ; // Entrada Rst = 0 me lleva al estado de restauración S0
PRESENT S2
OUT Naranja ; // No olviden el ;
IF Rst NEXT S3; // Si hay mas variables usar un operador lógico ej.
DEFAULT NEXT S0 ; // Rst & Q3
PRESENT S3
OUT Naranja, Verde ; // y continuamos con los demás estados
IF Rst NEXT S4;
DEFAULT NEXT S0 ;
PRESENT S4
OUT Verde ; // observa que la salida solo depende del estado
IF Rst NEXT S5; // y no de las entradas.
DEFAULT NEXT S0 ;
PRESENT S5
OUT Naranja, Verde ; // Pero la transicion depende de las entradas y
IF Rst NEXT S6; // y tambien puede de los estados anteriores.
DEFAULT NEXT S0 ;
PRESENT S6
OUT Naranja ; /* Forzo la Salida Naranja */
IF Rst NEXT S7;
DEFAULT NEXT S0 ;
PRESENT S7
OUT Rojo, Naranja ; /* Forzo la Salidas Rojo y Naranja */
IF Rst NEXT S8;
DEFAULT NEXT S0 ;
PRESENT S8
OUT Rojo, Cuenta; /* Forzo la Salidas Rojo y Cuenta */
IF Rst NEXT S1;
DEFAULT NEXT S0 ;
}
Ahora veamos el otro caso, la declaración de los estados es el mismo
pero las transiciones no lo son
SEQUENCE estados
{
PRESENT S0
// Entrada Rst= 1 lleva la transición al estado S1
IF Rst NEXT S1 OUT Rojo ; // y la salida cambia con la transición
// como cuando definimos entrada /salida
DEFAULT NEXT S0 ; // Entrada Rst = 0 me mantiene en el mismo estado
PRESENT S1
IF Rst NEXT S2 OUT Rojo, Naranja ;
DEFAULT NEXT S0 ; // Entrada Rst = 0 me lleva al estado de restauración S0
PRESENT S2
IF Rst NEXT S3 OUT Naranja ; // Si hay mas variables usar un operador lógico ej.
DEFAULT NEXT S0 ; // Rst & Q3
// y continuamos con los demás estados
PRESENT S3
IF Rst NEXT S4 OUT Naranja, Verde;
DEFAULT NEXT S0 ;
PRESENT S4
// observa que la salida depende del estado anterior y la(s) entrada(s)
IF Rst NEXT S5 OUT Verde ;; // que causan la transición.
DEFAULT NEXT S0 ;
PRESENT S5
IF Rst NEXT S6 OUT Naranja, Verde ; // También que se usa DEFAULT como si
DEFAULT NEXT S0 ; // fuera el "ELSE" del condicional "IF"
PRESENT S6
IF Rst NEXT S7 OUT Naranja ;
DEFAULT NEXT S0 ;
PRESENT S7
IF Rst NEXT S8 OUT Rojo, Naranja ;
DEFAULT NEXT S0 ;
PRESENT S8
IF Rst NEXT S1 OUT Rojo, Cuenta; // fácil verdad?
DEFAULT NEXT S0 ;
}