[MÚSICA] Hola de nuevo. En esta sesión abordaremos una selección de las principales sentencias del lenguaje VHDL y empezaremos por las sentencias secuenciales. Antes de empezar haremos algunos comentarios en torno al comportamiento secuencial versus el concurrente. En el mundo hardware las puertas y dispositivos físicos funcionan de forma concurrente a lo largo del tiempo, mientras que los lenguajes software tradicionales, los programas, son descripciones funcionales secuenciales que se materializan ejecutando una sentencia después de otra. En el caso del VHDL conviven ambos mundos, el concurrente y el secuencial, donde las descripciones se realizan con sentencias diferenciales, sentencias secuenciales y sentencias concurrentes. Las sentencias secuenciales son sentencias similares a los lenguajes de software del tipo if, case, loop, exit, return, y se interpretan secuencialmente, es decir, el orden de ejecución es importante para los resultados obtenidos. Estas solo se usan en funciones, procedures, y processes, los processes serán uno de los bloques más importantes de este lenguaje. Las sentencias concurrentes están orientadas a describir o modelar hardware donde componentes, bloques y procesos trabajan simultáneamente a lo largo del tiempo. Sentencias seleccionadas: los procesos, asignaciones a señal e instanciación a componentes serán las más importantes. Estas sentencias solo aparecen en la unidad de diseño llamada arquitectura. Y algunas sentencias secuenciales tienen su equivalente en las concurrentes. La simulación del VHDL se basa únicamente en procesos, y el process es una sentencia concurrente. Para ello cada sentencia concurrente se convierte a su proceso equivalente para simular todas las sentencias concurrentes se convierten a sus procesos equivalentes, y la simulación dirigida por eventos del VHDL solo gestiona un conjunto de procesos concurrentes. Veamos también cuál es la estructura general de un modelo VHDL antes de ir al detalle de las sentencias. Como ya hemos dicho, todo módulo VHDL está definido por una entity o entidad, donde fundamentalmente se define la interface con su entorno, principalmente los puertos de entrada/salida. Toda entidad tendrá al menos una arquitectura asociada donde se definirá la funcionalidad del módulo. Dicha funcionalidad se describe entre el begin y el end, y en esta parte solo pueden aparecer sentencias concurrentes. Así por ejemplo en el cuadro de la derecha podemos ver sentencias de asignación concurrente a señal o diversos procesos que son concurrentes entre sí. El orden de escritura de todas las sentencias de una arquitectura es irrelevante, pues todas son concurrentes y como tales se simulan. En cambio dentro de los procesos, se aglutinan sentencias secuenciales y estas sí que se ejecutan o simulan según el orden en que se han escrito. Luego aquí el orden es importante. Por lo tanto diremos que en una arquitectura se describe de forma concurrente, modelos de hardware concurrente, mientras que en un proceso se describe mediante una secuencia de instrucciones y de forma más algorítmica una determinada funcionalidad. Así pues el proceso como tal es una sentencia concurrente que aglutina código secuencial que define la función de dicho proceso. Después de estas aclaraciones previas, veamos algunas sentencias secuenciales que pueden aparecer en procesos, funciones y procedimientos. En este curso nos centraremos en los procesos, aunque haremos uso de alguna función predefinida en los paquetes estándar. Las principales sentencias secuenciales que detallaremos a continuación serán las asignaciones a variable y señal, la sentencia wait, el if then else, el case, el loop, y por último muy brevemente funciones, procedimientos y la sentencia assert. La asignación a variable es exactamente igual a una asignación a variable en software, es decir el valor asignado se instala inmediatamente como contenido de la variable en cuestión. Aquí tenemos algunos ejemplos de variables que reciben o valores literales o resultados de expresiones aritméticas o expresiones en las que interviene alguna función. Veamos ahora la asignación a señal. En este caso, en lugar de producir un cambio inmediato en el valor de la señal, lo que se hace es proyectar a futuro un nuevo evento en el driver asociado a cada señal. Pero, ¿qué es un evento? Un evento es una pareja de datos tiempo-valor cuyo significado es que en el tiempo ti indicado la señal toma el valor vi asociado. ¿Y qué es el driver de una señal? A diferencia de las variables, que solo son posiciones de memoria con un nombre concreto, que cambian de valor de forma inmediata cuando hay una asignación y lo conservan hasta que les afecta otra asignación, una señal requiere de una estructura de memoria más compleja, pues debe ser capaz de almacenar distintos valores de futuro. Por lo tanto valores que irá asumiendo en distintos instantes de tiempo. Visto así, el driver de una señal es una cola de eventos pares tiempo-valor, como vemos aquí. Si observamos la sintaxis de una asignación a señal, vemos que estas llevan asociada una cláusula temporal, un after, que indica en qué instante de tiempo o con qué retardo ese nuevo valor debe aparecer en la señal, luego con qué retardo dicho valor debe figurar en el driver de la señal. Si no se indica retardo alguno, se supone que es con retardo "0", y en ese caso el nuevo valor se instalaría al principio de la cola de eventos del driver. Pero seguiría siendo un valor proyectado a futuro, aunque este sea inmediato. Este tipo de respuesta ideal con retardo "0" en VHDL se conoce como delta-delay o retardo-delta. En VHDL tienes dos modelos de retardo, el transporte y el inercial, que no vamos a analizar en detalle pero que definiremos diciendo que el retardo inercial es el retardo asociado a una asignación y se considera el retardo tal que si sobre la señal asignada se producen pulsos inferiores o iguales a dicho retardo, estos se filtran y no se proyectan sobre la señal asignada. El otro modelo de retardo es el transport y en este caso, cualquier pulso que se envíe a una señal con este modelo, se transfiere a la misma con el retardo indicado pero sin filtrar los pulsos inferiores al mismo. En este ejemplo de aquí observamos en primer lugar que cargamos el driver de la señal con esta sentencia, y a continuación realizamos asignaciones de la señal A con distintos modelos de tiempo sobre las señales B1, B2 y B3. En general utilizaremos el retardo inicial o bien el retardo inercial con pulso mínimo, que corresponden a los casos B2 y B3 de este ejemplo. En el caso B1 es un retardo con modelo transport y aquí dejaremos pasar a la salida B1 cualquier cambio en la señal A. En el B2 vemos que el retardo es un retardo inicial y se considera que el tiempo mínimo que tiene que estar estable el valor que se asigna es el correspondiente al retardo de la cláusula after, que hemos dicho que eran 10 nanosegundos. Y por ello en B2 se eliminan los pulsos de entrada inferiores a 10 nanosegundos. Esto es lo que vemos en la señal B2. En cambio en B3, tenemos un retardo inercial con pulso mínimo de 5 nanosegundos y el retardo de 10, y es por ello que en B3 solo se eliminan aquellos pulsos que son iguales o inferiores a 5, este sería este caso de aquí. La sentencia wait es muy importante para sincronizar el funcionamiento de los procesos concurrentes en VHDL. Y ya sabemos que todas las sentencias concurrentes se convierten a sus procesos equivalentes antes de proceder a su simulación. Luego cuando se simula solo se simulan procesos concurrentes. Esta sentencia indica el punto donde el proceso en cuestión debe suspenderse o detenerse así como las condiciones para su reactivación. En un proceso puede haber más de una sentencia wait. Y aquí tenemos la sintaxis de esta sentencia pero veamos directamente algunos ejemplos sobre sus distintas posibilidades. El wait sin ninguna otra explicación es un wait sin condición de reactivación. En este caso el proceso se suspende indefinidamente. El wait on a, b, el proceso se detiene al llegar a este wait y se reactivará si y solo si hay algún evento en las señales a o b. El wait for 10 nanosegundos, una vez detenido el proceso en este wait, se dejan transcurrir 10 nanosegundos y entonces el proceso se reactiva y sigue en secuencia. Y por último el wait until clock igual a 1, este wait detiene el proceso y se queda sensible a evento en la señal clock y que se cumpla una condición, que clock sea 1. De hecho que haya un evento en la señal clock y que clock sea 1, es equivalente a decir que hemos detectado un flanco de subida en la citada señal clock. Por lo tanto esta estructura es una de las típicas para identificar flancos de subida en una determinada señal. [AUDIO EN BLANCO]