CASE más instrucciones WAIT

0

Estoy desarrollando un modelo de simulación de un componente que necesito en mi diseño. Para hacerlo rápido y simple, decidí crearlo solo de manera conductual (por ejemplo, no sintetizable).

Para hacerlo, estoy usando una sentencia CASE (que representa un FSM) con sentencias WAIT dentro.

main : PROCESS
BEGIN 
    CASE state IS
         WHEN S0 =>
            WAIT UNTIL start = '1';
            state <= S1;

         WHEN S1 =>
            WAIT UNTIL stop = '1';
            state <= S2;

         WHEN S2 =>

            ...

         WHEN OTHERS =>
    END CASE;
END PROCESS;

El problema es que el estado ingresa S1 cuando se valida la señal start pero no ingresa S2 cuando se confirma stop .

Siempre pensé que el uso de una instrucción WAIT en un CASE atascaba el proceso en un estado determinado hasta que la condición es válida, pero este ejemplo muestra que estoy equivocado. ¿Qué piensan ustedes de esto?

    
pregunta A. Kieffer

2 respuestas

1

Bueno ... finalmente encontré el problema.

Para aquellos que también podrían preguntarse por qué esto no funciona, de hecho, solo necesita una declaración WAIT al final del proceso (fuera de la declaración CASE).

Lo que pasa es que cuando start sube, state se actualiza realmente y toma su nuevo valor: S1. Sin embargo, como no estoy usando ninguna lista de sensibilidad, el proceso se está ejecutando de forma indefinida y al mismo tiempo que se actualiza state , el proceso vuelve a S0 esperando otra señal start ...

Es por eso que solo necesitas esto al final:

    ...
    END CASE
WAIT FOR time_value;
END PROCESS;
    
respondido por el A. Kieffer
1

Primero, algunos preliminares.

La declaración wait espera a que un evento y la condición sea verdadera. Entonces, si no hay evento, la condición no será evaluada. Por lo tanto, si start ya es 1 al ingresar S0, se detendrá en la declaración wait hasta que start cambie y se convierta en 1.

También, como señalé en mi comentario, la asignación de señales no se produce hasta el final del paso de tiempo. Las asignaciones de señal son sin bloqueo . Es decir, la asignación no bloquea la ejecución hasta que se completa la asignación. Como lo ha escrito, tomará 2 cambios en start yendo a 1 para provocar una transición al estado S1. Ajusté su código para agregar algunas declaraciones de informe y lo puse en un banco de pruebas. Aquí está el código:

main : PROCESS
BEGIN
  while true loop
    CASE state IS
         WHEN S0 =>
            report "Entering S0, waiting for start";
            WAIT UNTIL start = '1';
            state <= S1;

         WHEN S1 =>
            report "Entering S1, waiting for stop";
            WAIT UNTIL stop = '1';
            state <= S2;

         WHEN OTHERS =>
    END CASE;
  end loop;
END PROCESS;

Ahora, el banco de pruebas solo pulsa start dos veces (usando pulsos anchos de 1 ps, así que '0' en el momento 0, '1' en el tiempo 1 ps, '0' en el tiempo 2 ps y '1' en el tiempo 3 ps). Mira lo que pasa:

VSIM 1> run 5 ps
# ** Note: Entering S0, waiting for start
#    Time: 0 ps  Iteration: 0  Instance: /foo
# ** Note: Entering S0, waiting for start
#    Time: 1 ps  Iteration: 1  Instance: /foo
# ** Note: Entering S1, waiting for stop
#    Time: 3 ps  Iteration: 1  Instance: /foo

¿Ver la transición a S1? Esto se debe a que tu código está haciendo esto.

  • Supongamos un estado inicial de S0
  • Espera a que start cambie y se convierta en 1
  • Programe state para ir a S1. El estado de la nota aún no es S1. La asignación sin bloqueo permite que la ejecución continúe antes de que se complete la asignación.
  • Reinicia el proceso.
  • El estado sigue siendo S0 (la actualización programada a state aún no se ha producido).
  • Espere a que start cambie y se convierta en 1. Esto completa el intervalo de tiempo y ahora state cambia a S1.
  • Programe state para ir a S1. Ya es S1.
  • Reinicia el proceso.
  • El estado ahora es S1. Espere a que stop cambie y se convierta en 1. Esto completa el intervalo de tiempo y ahora state cambia (nuevamente) a S1.

Por lo tanto, hay dos maneras de solucionarlo. La primera es asignar state antes a la espera de que cambie la señal. Por ejemplo:

main : PROCESS
BEGIN
  while true loop
    CASE state IS
         WHEN S0 =>
            report "Entering S0, waiting for start";
            state <= S1;
            WAIT UNTIL start = '1';

         WHEN S1 =>
            report "Entering S1, waiting for stop";
            state <= S2;
            WAIT UNTIL stop = '1';

         WHEN OTHERS =>
    END CASE;
  end loop;
END PROCESS;

Ahora, mira lo que sucede con el mismo estímulo en start :

VSIM 1> run 5 ps
# ** Note: Entering S0, waiting for start
#    Time: 0 ps  Iteration: 0  Instance: /foo
# ** Note: Entering S1, waiting for stop
#    Time: 1 ps  Iteration: 1  Instance: /foo

De hecho, este es el tipo de estilo recomendado para la inferencia de registros. Primero asigne el nuevo valor, luego espere el evento.

Pero como este es un modelo, podemos ir uno más lejos. Podemos usar un variable y luego podemos hacer una asignación de bloqueo . Esto bloquea la ejecución hasta que se completa la asignación. Por ejemplo:

main : PROCESS
  variable state : states := S0;
BEGIN
  while true loop
    CASE state IS
         WHEN S0 =>
            report "Entering S0, waiting for start";
            WAIT UNTIL start = '1';
            state := S1;

         WHEN S1 =>
            report "Entering S1, waiting for stop";
            WAIT UNTIL stop = '1';
            state := S2;

         WHEN OTHERS =>
    END CASE;
  end loop;
END PROCESS;

Tenga en cuenta que he hecho de state una variable y ahora uso la asignación de bloqueo ( := ). Y el resultado:

VSIM 1> run 5 ps
# ** Note: Entering S0, waiting for start
#    Time: 0 ps  Iteration: 0  Instance: /foo
# ** Note: Entering S1, waiting for stop
#    Time: 1 ps  Iteration: 1  Instance: /foo

De hecho, puedo poner la asignación antes o después de la declaración wait y obtener el mismo resultado.

Tu solución para agregar wait for time_value es problemática. Introduce un retraso donde uno no es necesario y quizás no deseable. Te recomiendo que cambies tu modelo al ejemplo basado en variable para un comportamiento más obvio.

    
respondido por el PlayDough

Lea otras preguntas en las etiquetas