En esta entrada voy a mostrar como simular un diseño en VHDL utilizando el archivo de formas de onda o waveform file .vwf.
Empecemos con el sistema que hemos de programar:
El primer circuito digital que hemos de implementar en este curso... ¡qué emoción! |
Quizá digan que el sistema a diseñar ahora es demasiado simple..., pero para empezar está bien. Más adelante nos toparemos con sistemas más desafiantes, y antes de querer correr, deberíamos primero gatear. Así que empecemos...
Llamemos a la salida de esta sistema Z. Entonces, gracias a nuestros conocimientos en circuitos digitales sabemos que Z= (A and C) or B. Esta descripción booleana de nuestro resultado nos ayudará a obtener la tabla de verdad de nuestro circuito. Como todos sabemos, la talba de verdad contiene toda la información que hay que tener sobre un sistema a fin de conocer su funcionamiento. Tras asignar los valores , obtenemos la siguiente tabla de verdad:
Tabla de verdad del circuito. |
Con todo lo hallado, tenemos ya una descripción completa del circuito propuesto. Ahora... ¿y en VHDL?
Primera forma para codificarlo
Abrimos el Quartus II, y seleccionamos New => VHDL File. Ello nos proveerá del lienzo en el que hemos de pintar nuestro primer ejemplo.
library ieee; use ieee.std_logic_1164.all; entity primerejemplo1 is port( a,b,c :in std_logic; z :out std_logic); end primerejemplo1; architecture arqej1 of primerejemplo1 is begin z<=(a and c)or b; end arqej1;
Como se puede apreciar, z recibe exactamente la función booleana obtenida líneas arriba. Esta forma de programar está muy bien, pero complica las cosas cuando hablamos de circuitos más complejos, con más entradas, o circuitos secuenciales.
Al guardar el archivo (recordar hacerlo con el mismo nombre de la entidad), Quartus II nos preguntará si deseamos crear un proyecto con este archivo. Para simular el diseño, primero debemos compilarlo, y toda compilación sólo puede darse en un proyecto. Entonces la damos Sí. Ello lanzará al Porject Wizard descrito en la entrada anterior... Seguir los pasos descritos en dicha entrada para crear el proyecto satisfactoriamente. En este caso, yo llamé al proyecto como primerejemplo, y elegí al archivo que acabamos de crear como archivo top-file.
Nota: Como quizá lo habrán notado, esta es otra forma de crear proyectos... Esta forma es la más segura para evitar errores de compilación y evitar marearse con todas las entidades que quisieramos añadir al proyecto: Escribimos nuestro código en VHDL, lo guardamos, pero no desmarcamos la opción que sugerí desmarcar en la entrada anterior. Luego, aceptar la petición para crear el proyecto a partir de ese archivo. En la ventana del Project Wizard que les saldrá, tener cuidado al momento de escribir los nombres. Sugiero que no llamen al proyecto con el nombre del archivo .VHD que acaben de crear, debido a que si quieren añadir más archivos al proyecto, el esquema de jerarquias no quedará muy bien que digamos... Guardar con un nombre genérico al proyecto, por ejemplo, si el código que hemos hecho implementa un contador BCD de 4 bits y lo hemos guardado como contadorBDC4bits.vhd; no llamar al proyecto así, sino, por ejemplo, proyecto_contadores. Eso si, en la casilla inferior elegir como archivo top a la entidad que hallamos creado (en este caso sí sería contadorBCD4bits). Si hacen esto, si mañana más tarde desean agregar otro archivo al proyecto e implementar un diseño jerárquico, podrán hacerlo sin el temor de que se asigne mal la jerarquía.
Bueno... sigamos... Luego de esto queda compilar... para ello hacemos click en un botón similar la PLAY, de colo morado, y listo... a esperar...
Iniciando la compilación... |
Si se ha hecho bien todo lo mencionado anteriormente, la compilación solo arrojará advertencias, mas no errores. Estas advertencias saltan debido a que muchas de las herramientas especiales de síntesis están deshabilitadas debido a que la versión del Quartus II es la versión gratis y no la de subscripción... Otras advertencias pueden relacionarse con las asignaciones de los pines del diseño.
NOTA: En caso de que salga algún error, o la compilación tome mucho tiempo, para los fines de la presente entrada bastará con emplear la herramienta Start Analysis and Síntesis. Para ello, hacer click en el botón que está al lado del botón de Compilación. Si aun así se obtienen errores, entonces deberá revisar el fichero .vhd, en búsqueda de algún error.
Iniciar análisis y síntesis. |
Mientras no tengamos errores, por ahora, digamos que todo va bien... Al final de la compilación, Quartus II nos proporcionará un reporte con información sobre la síntesis.
Reporte de compilación para nuestro primer ejemplo. |
¿Qué parámetros deberían tomarse en cuenta? Inicialmente, de acuerdo al FPGA o CPLD elegida para la compilación (esto se elige en el Project Wizard o haciendo click después en Assignments=>Device), el reporte nos dice el área ocupada por nuestro circuito. Esta área representa el total de elementos lógicos empleados para sintetizar el sistema, respecto a la cantidad total de elementos lógicos de la FPGA o CPLD. En este caso, vemos que nuestro circuito solo toma un elemento lógico, lo cual representa menos del 1% del total del área del FPGA, en este caso una Cyclone IV GX. Este caso nuestro ejemplo ni siquiera le hizo cosquillas a la FPGA, pero conforme incrementos la complejidas de los diseños, veremos que este parámetro será determinante al elegir entre uno u otro FPGA o CPLD.
Hecho esto, queda simular nuestro diseño. Para ello haremos uso de los waveform files o VWF. files. Para crear estos archivos, debemos abrir otra IDE: Altera University Program Simulator. Puede descargar este software gratuitamente desde la página de Altera. Este simulador externo es necesario para todas las versiones recientes del Quartus II, debido a que estas IDE's ya no vienen con el simulador incluido (recuerdo que la versión 9.1 venía con el simulador integrado... pero a partir de la versión 11.0 ya no más).
Hecho esto, al ejecutar el programa les saldrá una ventana tipo CMD, tras la cual la verdadera IDE simuladora arrancará.
No se asusten si ven esta ventana... a través de esta el simulador arrancará... |
Luego verán la siguiente plataforma, que es en la que crearán el archivo waveform para simular su diseño.
Qsim, para simular nuestros diseños en VHDL y ver si hacen lo que supuestamente deberían hacer... |
El primer paso es cargar nuestro proyecto. Para ello, hacer click en File => Open Project.
Buscar el proyecto que hemos creado y cargarlo. El programa les avisará mediante:
>> Opened project: primerejemplo (Revision: primerejemplo1)
Luego, hacemos click en New (la hoja en blanco). Con esto, nos saldrá una ventana con un waveform en blanco.
Ventana de creación de un waveform file. |
Un waveform file es básicamente un diagrama de tiempos en el que asignaremos a las señales de entrada de nuestro sistema valores que cambien en el tiempo, para observar como varía la salida. (Recordar los diagramas de tiempo de las memorias RAM, algo parecido...).
Bueno, seguimos... Ahora, hacemos doble click sobre el espacio en blanco rotulado por Name. Ello hará saltar la siguiente ventana:
Ventana para seleccionar los puertos que hemos de usar para simular. |
Seleccionar el Node Finder. En Filter, elegir Pins: all, luego hacer click en List. Hecho eso aparecerán todos los puertos creados en el proyecto. Hacer click en >>, luego en OK para finalizar.
Veremos todos los puertos que hemos creado en nuestro proyecto... |
Hecho esto, la ventana quedará lista para determinar las formas de onda para simular nuestro proyecto.
Ya estamos listos para crear nuestras señales de prueba... |
Notar que nuestra salida Z tiene valor desconocido. Ello debido que aun no se simulado nada. Debemos dejarlo así para evitar que el simulador lo interprete como colisión de señal y nos bote un error.
Por defecto, el simulador elige un tiempo de simulación de 1us. Si quieren ampliar este intervalo, hacer click en Edit => Set End Time.
Elegir cuanto tiempo quieres simular... |
Por ahora lo dejaremos en 1 us.
Dentro del cuadro rojo, los posibles niveles que le podemos asignar a nuestras entradas... interesante ¿no creen? |
Para asignar los niveles a las señales, resaltar el intervalo que deseen aignar, y elegir el nivel deseado en la parte indicada por el recuadro rojo.
Para este caso, elegí los siguiente para las tres entradas:
Señales con sus valores ya definidos... ahora sí, ¡a simular! |
A la entrada a le asigné un reloj de 100ns de periodo, a la entrada b, reloj de 200ns, y a la entrada c, un reloj de 400ns. Hecho esto, guardamos el archivo con el mismo nombre de la entidad que queremos simular y cerramos el editor de vwf.
En la ventana principal del simulador, hacer click Assign => Simulator Settings...
Ajustes de simulación. |
En esta ventana, elegir el archivo .vwf que hemos creado. En este caso,
primerejemplo1.vwf. La opción de abajo es importante. Existen dos tipos
de simulación con archivos .vwf: la simulación funcional y la simulación
temporal. La primera (Functional), simulará asumiendo que todos los
elementos lógicos son ideales, y que por ende, no tienen retardos de
propagación. Este tipo de simulación se usa para verificar si la
estructura de tu diseño es correcta o no. La simulación temporal
(Timing) en cambio sí toma en cuenta estos retardos. Esta simulación es
más realista, y se usa para contrastar si tu diseño se ve afecto o no en
su desempeño debido a estos retardos.
En este caso elegiré la simulación temporal.
Hecho esto queda hacer click en la gran flecha azul para inicar la simulación. Lamentablemente os saldrá un error. Ello debido a que la familia Cyclone no es soportada por el simulador. Para corregir el error, simplemente compilar el diseño sobre otro FPGA o CPLD. En este caso, elegiremos un CPLD de la familia MAX3000A. Para hacer el cambio, hacer click en Assignments => Device.
Compilamos nuevamente, y leemos el reporte. Vemos que esta vez se consumió el 3% de área del CPLD. Ello debido a que solo tiene 32 macroceldas (para los CPLD's, ya no son elementos lógicos, sino macroceldas).
32 macroceldas ofrecidas por la MAX3000A, 1 macrocelda destinada a nuestro proyecto. |
Hecho esto, en el simulador recargamos el proyecto, recargamos el archivo .vwf y le damos click a la gran flecha azul. Esta vez la simulación será exitosa.
Aun se puede ver en rojo el error producido por querer simular en una FPGA de la familia Cyclone. |
Es importante lograr el 100% de covertura en la simulación, a fin de que todas las posibilidades sean simuladas. En este caso, para las formas de onda creadas, se obtuvo un 100.00% de coverage. Si no se hubiese logrado, deberíamos cambiar las formas de onda de las entradas, buscando cubrir todas las posibilidades. Bueno, al acabar de simular, no saltará el reporte de simulación con la forma de onda de la salida.
Reporte de simulación... ¡yeah! Resultados esperados... diseño funcionando bien... |
Se aprecia en el diagrama obtenido que la salida se comporta según lo esperado, lo cual verifica que el diseño está bien. Acercándonos más en la respuesta, podemos medir los retrasos de propagación de nuestro diseño. Para ello, agregamos punteros. Para ello, hacemos doble click en el espacio en blanco entre la barra en donde están los tiempos, y el espacio en donde dibujamos nuestras formas de onda. Aparece un puntero en dicha posición. Luego, hacemos click en Edit => Snap to grid para hacer que los punteros puedan posicionarse en cualquier punto (si Snap to grid está seleccionada, los punteros se posicionarán solo en los ejes marcados por las líneas verticales punteadas (grid)). El segundo puntero marcará la diferencia en tiempo respecto al puntero master (para diferenciarlo, el puntero master tiene un indicar de posición en la parte superior y además, tendrá una línea azul bien definida, mientras que los punteros secundarios serán líneas delgadas azules).
Añadiendo punteros. |
En este caso, el ratardo, medido usando punteros, es de 3.584ns.
Con esto, la simulación queda finalizada.
Segunda y tercera de codificación para el primer ejemplo
Ahora, utilizaremos una señal para codificar el circuito.
library ieee; use ieee.std_logic_1164.all; entity primerejemplo2 is port( a,b,c :in std_logic; z :out std_logic); end primerejemplo2; architecture arqej of primerejemplo2 is signal ac:std_logic; begin ac<= a and c; z<=ac or b; end arqej;
Creamos la señal ac, y le asignamos el producto lógico de las entrada a y c. Luego, obtenemos nuestra salida z a partir de ella.
Al guardar el diseño, lo hacemos dentro del proyecto primerejemplo, y luego le asignamos la prioridad este archivo (lo seteamos como archivo top-level). Para ello, ver la siguiente imagen:
Set a Top-level Entity... |
Compilar y seguir los pasos anteriores para simular. El resultado es el siguiente:
Mismo resultado al anterior... eso implica que los diseños son equivalentes... |
La última forma para diseñar el sistema del primer ejemplo es usando la tabla de verdad:
library ieee; use ieee.std_logic_1164.all; entity primerejemplo3 is port( abc :in std_logic_vector(2 downto 0); z :out std_logic); end primerejemplo3; architecture arqej of primerejemplo3 is begin with abc select z<= '1' when "010", '1' when "011", '1' when "101", '1' when "111", '0' when others; end arqej;
Esta vez se definió la entrada como un vector de 3 bits. Vemos que la salida z se asgina según los valores que tome el vector abc de acuerdo a la tabla de verdad hallada. No se preocupen por entender como funciona esa manera de asignación. En las entradas que vienen me enfocaré en sí al diseño en VHDL, explicándoles todas las maneras de asignación posibles, así como estilos de programación y otros asuntos de interés.
Tras compilar y simular, se verifica que este diseño también es equivalente a los dos planteados previamente.