SÍNTESIS Y DESCRIPCIÓN DE CIRCUITOS DIGITALES UTILIZANDO VHDL IEC FRANCISCO JAVIER TORRES VALLE 2001 SINTESIS Y DESCRIPCIÓN DE CIRCUITOS DIGITALES UTILIZANDO VHDL A N T E C E D E N T E S En los últimos diez años la industria electrónica ha tenido una gran evolución en el desarrollo de sistemas digitales; desde computadoras personales, sistemas de audio y vídeo hasta dispositivos de alta velocidad para las comunicaciones. Productos hechos con una alta tecnología que permite aumentar la funcionalidad, disminuir costos, mejorar el aprovechamiento de la energía, así como una marcada tendencia hacia la miniaturización. Esto ha sido posible gracias a la implementación de herramientas de diseño asistidos por computadora, conocidas como herramientas CAD (Computer Aided Design), aunque específicamente se hace uso de herramientas EDA (Electronic Design Automation), que es el nombre que se le da a todas las herramientas CAD para el diseño de sistemas electrónicos. Este software de diseño electrónico que facilita a los ingenieros el desarrollo de circuitos es cada vez mas sofisticado y, además, contamos con computadoras cada vez más veloces y de mayor capacidad de procesamiento. Ambos, hardware y software, constituyen actualmente herramientas muy importantes que simplifican el trabajo de diseño electrónico. Además de facilitar el trabajo, el uso de herramientas EDA también aceleró los procesos de diseño. Esta situación condujo a adoptar nuevas metodologías para el diseño y evaluación de los circuitos electrónicos. El uso de las herramientas EDA junto con los dispositivos lógicos programables, que pueden ser utilizados en diferentes aplicaciones e inclusive reprogramados, cambiaron bastante el concepto de diseño de circuitos digitales. El presente trabajo considera los dispositivos lógicos programables, enfocándonos en los PLDs, CPLDs y FPGAs. Ya que el principal motivo por el que debemos aprender a utilizar VHDL es el de diseñar circuitos lógicos utilizando este tipo de dispositivos. Se expondrán los estilos elementales de codificación, exponiendo las principales características de VHDL como lenguaje para síntesis de circuitos. Finalmente se desarrolla la implementación de filtros digitales utilizando FPGAs. VHDL es un lenguaje que se creó para el diseño, modelado y documentación de circuitos complejos. Actualmente se le utiliza para la síntesis de circuitos digitales utilizando dispositivos lógicos programables. Es así como los dispositivos lógicos programables y VHDL, Very High Speed Integrated Circuit (VHSIC) Hardware Description Language, constituyen los elementos fundamentales para estas nuevas metodologías de diseño. IEC FRANCISCO JAVIER TORRES VALLE i SINTESIS Y DESCRIPCIÓN DE CIRCUITOS DIGITALES UTILIZANDO VHDL Í N D I C E ANTECEDENTES i 1. LENGUAJES DE DESCRIPCIÓN DE HARDWARE 1 1.1. INTRODUCCIÓN. 2 1.2. EL CONCEPTO DE HERRAMIENTAS CAD-EDA. 2 1.3. LENGUAJES DE DESCRIPCIÓN DE HARDWARE. 4 1.3.1. 2. VENTAJAS DE LOS HDLS 1.4. VHDL 5 1.5. METODOLOGÍA DE DISEÑO UTILIZANDO VHDL 6 DISPOSITIVOS LÓGICOS PROGRAMABLES 9 2.1. CONCEPTOS FUNDAMENTALES 10 2.2. DISPOSITIVOS LÓGICOS PROGRAMABLES 10 2.2.1. MATRIZ GENÉRICA PROGRAMABLE 2.3. COMPLEX PROGRAMMABLE LOGIC DEVICES 10 11 2.3.1. MATRIZ DE INTERCONEXIONES PROGRAMABLES 11 2.3.2. BLOQUES LÓGICOS 11 2.3.3. DISTRIBUCIÓN DE PRODUCTOS 12 2.3.4. MACROCELDAS 12 2.3.5. CELDA DE ENTRADA/SALIDA 13 2.4. FIELD PROGRAMMABLE LOGIC DEVICES 2.4.1. 3. 5 CELDAS LÓGICAS 13 14 SINTAXIS DEL LENGUAJE 17 3.1. INTRODUCCIÓN A LA DESCRIPCIÓN EN VHDL DE CIRCUITOS DIGITALES 18 3.1.1. MULTIPLEXORES 18 3.1.2. COMPARADORES 19 3.1.3. EL ESTILO DE “PROGRAMACIÓN” EN VHDL 20 3.2. IDENTIFICADORES 21 3.3. OBJETOS DE DATOS 21 3.3.1. CONSTANTES IEC FRANCISCO JAVIER TORRES VALLE 21 ii SINTESIS Y DESCRIPCIÓN DE CIRCUITOS DIGITALES UTILIZANDO VHDL 3.3.2. VARIABLES 22 3.3.3. SEÑALES 22 3.3.4. ALIAS 22 3.4. TIPOS DE DATOS 22 3.4.1. TIPOS ESCALARES 22 3.4.2. TIPOS COMPUESTOS 25 3.4.3. SUBTIPOS 27 3.4.4. TIPOS PREDEFINIDOS EN VHDL 27 3.4.5. TIPOS NO SOPORTADOS EN VHDL PARA SÍNTESIS 27 3.5. OPERADORES 28 3.5.1. OPERADORES LÓGICOS 28 3.5.2. OPERADORES DE COMPARACIÓN 28 3.5.3. OPERADORES DE ADICIÓN 28 3.5.4. OPERADORES DE MULTIPLICACIÓN 29 3.5.5. OPERADORES MISCELÁNEOS 29 3.5.6. OPERADORES DE ASIGNACIÓN 29 3.5.7. OPERADORES DE ASOCIACIÓN 30 3.5.8. OPERADORES DE CORRIMIENTO 31 3.5.9. OPERACIONES CON VECTORES 31 3.6. ATRIBUTOS 32 3.7. ENTIDADES 32 3.7.1. GENÉRICOS 33 3.7.2. PUERTOS 33 3.7.3. MODOS 33 3.8. ARQUITECTURAS 34 3.9. DESCRIPCIONES DE FLUJO DE DATOS 34 3.9.1. INSTRUCCIONES CONCURRENTES 35 3.9.2. ESTRUCTURAS DE EJECUCIÓN CONCURRENTE 35 3.9.3. ALU 35 3.10. DESCRIPCIONES COMPORTAMENTALES 38 3.10.1. INSTRUCCIONES SECUENCIALES 38 3.10.2. PROCESOS 38 3.10.3. DIFERENCIAS ENTRE SEÑALES Y VARIABLES 39 3.10.4. ESTRUCTURAS DE EJECUCIÓN SECUENCIAL 40 3.11. DESCRIPCIONES ESTRUCTURALES IEC FRANCISCO JAVIER TORRES VALLE 42 iii SINTESIS Y DESCRIPCIÓN DE CIRCUITOS DIGITALES UTILIZANDO VHDL 3.11.1. COMPONENTES 42 3.11.2. INSTANCIACIÓN DE COMPONENTES 43 3.11.3. SENTENCIAS DE GENERACIÓN 44 3.12. SUBPROGRAMAS 3.12.1. PROCEDIMIENTOS 47 3.12.2. FUNCIONES 47 3.12.3. LLAMADO A SUBPROGRAMAS 48 3.12.4. SOBRECARGA DE OPERADORES 50 3.13. LIBRERÍAS 4. 50 3.13.1. SÍNTESIS DE LIBRERÍAS EN WARP 50 3.13.2. PAQUETES 52 DESCRIPCIÓN DE CIRCUITOS DIGITALES 54 4.1. PROYECTOS EN WARP 5.0 55 4.2. SIMULACIÓN DE PROYECTOS 57 4.2.1. PROCESO DE SIMULACIÓN 57 4.3. COMPARADORES 60 4.4. MULTIPLEXORES 65 4.4.1. DESCRIPCIÓN DE FLUJO DE DATOS 65 4.4.2. DESCRIPCIÓN COMPORTAMENTAL 66 4.4.3. DESCRIPCIÓN ESTRUCTURAL 67 4.5. SUMADORES 5. 47 68 4.5.1. SUMADOR TOTAL 68 4.5.2. SUMADOR DE CUATRO BITS 69 4.5.3. SYNTHESIS OFF 70 4.6. REGISTROS 71 4.7. CONTADORES 73 4.8. ALU DE CUATRO BITS 76 4.8.1. DESCRIPCIÓN ESTRUCTURAL 77 4.8.2. DESCRIPCIÓN COMPORTAMENTAL 78 4.9. MÁQUINAS DE ESTADO 79 IMPLEMENTACIÓN DE FILTROS DIGITALES EN FPGA'S 83 5.1. INTRODUCCIÓN 84 5.2. ANTECEDENTES 84 IEC FRANCISCO JAVIER TORRES VALLE iv SINTESIS Y DESCRIPCIÓN DE CIRCUITOS DIGITALES UTILIZANDO VHDL 5.3. MARCO TEÓRICO 84 5.3.1. FILTROS FIR 84 5.3.2. FILTROS IIR 85 5.3.3. METODOLOGÍA DE DISEÑO PARA FILTROS DIGITALES 86 5.4. IMPLEMENTACIÓN EN FPGA'S 86 5.5. DISEÑO DE UN FILTRO PASA-BAJAS 86 5.6. RESULTADOS 93 CONCLUSIONES 95 BIBLIOGRAFÍA 97 IEC FRANCISCO JAVIER TORRES VALLE v CAPÍTULO I: LENGUAJES DE DESCRIPCIÓN DE HARDWARE I IEC FRANCISCO JAVIER TORRES VALLE LENGUAJES DE DESCRIPCIÓN DE HARDWARE 1 CAPÍTULO I: LENGUAJES DE DESCRIPCIÓN DE HARDWARE 1.1 INTRODUCCIÓN A mediados de los años setenta se produce una fuerte evolución en los procesos de fabricación de los circuitos integrados, promoviendo el desarrollo de circuitos digitales hasta la primera mitad de los años ochenta. En aquellas épocas el esfuerzo de diseño se concentraba en los niveles eléctricos para establecer características e interconexiones entre los componentes básicos al nivel de transistor. El proceso de diseño era altamente manual y tan sólo se empleaban herramientas como PSPICE para simular esquemas eléctricos con modelos previamente caracterizados a cada una de las distintas tecnologías. A medida que pasaban los años, los procesos tecnológicos se hacían más y más complejos. Los problemas de integración iban en aumento y los diseños eran cada vez más difíciles de depurar y de dar mantenimiento. Inicialmente los circuitos MSI (Medium Scale Integration) y LSI (Low Scale Integration) se diseñaron mediante el desarrollo de prototipos basados en módulos simples. Cada uno de estos módulos estaba formado por compuertas ya probadas, pero este método poco a poco iba quedándose obsoleto conforme aumentaba la complejidad y tamaño de los circuitos. A finales de los años setenta se constata el enorme desfase que existía entre tecnología y diseño. La considerable dificultad que puede llegar a tomar el fabricar un circuito de alta escala de integración, involucra riesgos y costos de diseño desmesurados e imposibles de asumir por las empresas. Es entonces, cuando diversos grupos de investigadores empiezan a crear y desarrollar los llamados “lenguajes de descripción de hardware”, lenguajes en los que no fuera necesario caracterizar eléctricamente cada componente del circuito al nivel de transistor para así enfocarse solamente en el funcionamiento lógico del sistema. Empresas tales como IBM con su IDL, el TI-HDL de Texas Instruments, ZEUS de General Electric, etc., así como los primeros prototipos empleados en las universidades, empezaron a desarrollarse buscando una solución a los problemas que presentaba el diseño de sistemas complejos. Sin embargo, estos lenguajes nunca alcanzaron el nivel de difusión y consolidación necesarios por motivos distintos. Unos, los industriales, por ser propiedad de la empresa permanecieron encerrados en ellas y no estuvieron disponibles para su estandarización y mayor difusión, en tanto que los universitarios IEC FRANCISCO JAVIER TORRES VALLE perecieron por no disponer de soporte ni mantenimiento adecuado. 1.2 EL CONCEPTO DE HERRAMIENTAS CAD-EDA CAD son las siglas de Computer Aided Design, o diseño asistido por computadora el cual constituye todo un proceso de trabajo utilizando técnicas de análisis apoyadas en gráficos mediante sofisticadas herramientas de software las cuales facilitan el estudio de los problemas asociados con el diseño en cuestión. El concepto CAD se relaciona con el dibujo como parte importante en el proceso de diseño pero, además, el diseño de un circuito debe cumplir con los requerimientos especificados por el equipo de diseño, por las normas de calidad existentes, los costos, etc. por lo que las herramientas CAD intervienen en todas las fases del diseño. Ya que no sólo son importantes por acelerar el desarrollo del sistema al permitir que varias personas puedan trabajar simultáneamente en distintas etapas del diseño sino que, además, es posible verificar el funcionamiento del circuito mediante la simulación del sistema. Todo esto simplifica la tarea del equipo de diseño y conduce a la conclusión del prototipo en menos tiempo. EDA, Electronic Design Automation, es el nombre que se le da a todas las herramientas de hardware y software en el diseño de sistemas electrónicos. Porque no sólo el software es importante, también lo es el hecho de que las computadoras cada día son más veloces y de mayor capacidad de procesamiento, lo cual influye en el proceso de diseño de circuitos electrónicos. El diseño de hardware tiene un problema fundamental, que no existe en desarrollo de software. Este problema es el alto costo del ciclo diseño desarrollo del prototipo pruebas reinicio del ciclo, ya que el costo del prototipo generalmente suele ser bastante elevado. Se impone la necesidad de reducir este ciclo de diseño para no incluir la fase de desarrollo del prototipo más que al final del proceso, evitando la repetición de varios prototipos que es lo que encarece el ciclo. Para ello se introduce la fase de simulación y verificación de circuitos utilizando herramientas EDA, de tal forma que no sea necesario implementar físicamente un prototipo para comprobar el funcionamiento del circuito. 2 CAPÍTULO I: LENGUAJES DE DESCRIPCIÓN DE HARDWARE En el ciclo de diseño de circuitos, las herramientas EDA están presentes en todas las fases. Primero en la fase de generación del sistema que puede representarse mediante un diagrama esquemático, a bloques o de flujo. A continuación se mencionan las principales características y finalidad de algunas herramientas EDA que intervienen en el diseño de circuitos. Se encuentran también en la fase de simulación y comprobación de circuitos, donde diferentes herramientas permiten verificar el funcionamiento del sistema. Estas simulaciones pueden ser de eventos, funcionales, digitales o eléctricas, de acuerdo al nivel de simulación requerido. Después están las herramientas EDA utilizadas en la síntesis y programación de circuitos digitales en dispositivos lógicos programables. Existen, además, las herramientas EDA orientadas a la fabricación de circuitos. En el caso del diseño de hardware estas herramientas sirven para la realización de PCBs (Printed Circuit Boards o placas de circuito impreso), o para desarrollar circuitos integrados de aplicación especifica conocidos como ASICs (Application Specific Integrated Circuits). Este ciclo de diseño de hardware se muestra en la figura 1.1. Son lenguajes mediante los cuales es posible describir el funcionamiento y estructura de un circuito eléctrico o digital. La descripción puede ser mediante bloques donde se muestra la arquitectura del diseño, o de comportamiento, es decir, se describe el funcionamiento del circuito en vez de especificar los elementos de los que está compuesto. SÍNTESIS SIMULACIÓN FUNCIONAL ANÁLISIS TEMPORAL ¿FUNCIONA? ¿FUNCIONA? II. si no III. Grafos y diagramas de flujo. Simulación de eventos. Estas herramientas se usan para la simulación de circuitos a grandes rasgos. En esta simulación, los componentes más importantes son elementos de alto nivel como discos duros, buses de comunicaciones, memorias RAM etc. si PROGRAMACIÓN DEL DISPOSITIVO no ¿FUNCIONA? Diagramas esquemáticos. Es la forma clásica de describir un diseño electrónico y la más extendida ya que era la única usada antes de la aparición de las herramientas de EDA. La descripción está basada en un “plano” donde se muestran los diferentes componentes utilizados en el circuito. IV. no Lenguajes de descripción de circuitos. Es posible describir un circuito o sistema mediante diagramas de flujo, redes de Petri, máquinas de estados, etc. En este caso sería una descripción gráfica y además sería comportamental, porque no es una descripción mediante componentes. IDEA DESCRIPCIÓN DEL CIRCUITO I. PRUEBAS AL DISEÑO ELABORACIÓN DEL PROTOTIPO si FINALIZA EL PROCESO DE DISEÑO Figura 1.1 Flujo de diseño en el desarrollo de sistemas electrónicos IEC FRANCISCO JAVIER TORRES VALLE V. Simulación funcional. Bajando al nivel de compuertas digitales se puede realizar una simulación funcional de las mismas. Este tipo de simulación comprueba la operación de circuitos digitales a partir del comportamiento lógico de sus elementos con el fin de comprobar el funcionamiento en conjunto del circuito mediante unos estímulos dados. Similar a lo que se realiza en un laboratorio. VI. Simulación digital. Esta simulación, también exclusiva de los circuitos digitales, es como la anterior con la diferencia de que se tienen en cuenta los retardos 3 CAPÍTULO I: LENGUAJES DE DESCRIPCIÓN DE HARDWARE de propagación de cada compuerta. Es una simulación muy cercana al comportamiento real del circuito y prácticamente garantiza el funcionamiento correcto del circuito en cuestión. En las herramientas EDA este tipo de simulación se conoce como análisis temporal o timing. VII. Simulación eléctrica. Es la simulación de más bajo nivel donde las respuestas del sistema se verifican al nivel de transistor. Sirven tanto para circuitos analógicos como digitales y su respuesta es prácticamente idéntica a la realidad ya que se prueban retardos de tiempo, niveles de voltaje, disipación de potencia, etc. VIII. Diseño de PCBs Con estas herramientas es posible realizar el trazado de pistas para la fabricación de placas de circuitos impresos. IX. Diseño de circuitos integrados Son herramientas EDA que sirven para la realización de circuitos integrados. Las capacidades gráficas de estas herramientas permiten la realización de las diferentes máscaras que intervienen en la realización de éstos. X. Diseño con dispositivos programables. Estas herramientas facilitan la programación de dispositivos, ya sean PALs, PLDs, CPLDs o FPGAs. 1.3 LENGUAJES DE DESCRIPCIÓN DE HARDWARE Los lenguajes de descripción de hardware (HDLs) son utilizados para describir la arquitectura y comportamiento de un sistema electrónico los cuales fueron desarrollados para trabajar con diseños complejos. Comparando un HDL con los lenguajes para el desarrollo de software vemos que en un lenguaje de este tipo un programa que se encuentra en un lenguaje de alto nivel (VHDL) necesita ser ensamblado a código máquina (compuertas y conexiones) para poder ser interpretado por el procesador. De igual manera, el objetivo de un HDL es describir un circuito mediante un conjunto de instrucciones de alto nivel de abstracción para IEC FRANCISCO JAVIER TORRES VALLE que el programa de síntesis genere (ensamble) un circuito que pueda ser implementado físicamente. La forma más común de describir un circuito es mediante la utilización de esquemas que son una representación gráfica de lo que se pretende realizar. Con la aparición de herramientas EDA cada vez más complejas, que integran en el mismo marco de trabajo las herramientas de descripción, síntesis, simulación y realización; apareció la necesidad de disponer de un método de descripción de circuitos que permitiera el intercambio de información entre las diferentes herramientas que componen el ciclo de diseño. En principio se utilizó un lenguaje de descripción que permitía, mediante sentencias simples, describir completamente un circuito. A estos lenguajes se les llamó Netlist puesto que eran simplemente eso, un conjunto de instrucciones que indicaban las interconexiones entre los componentes de un diseño. A partir de estos lenguajes simples, que ya eran auténticos lenguajes de descripción hardware, se descubrió el interés que podría tener el describir circuitos utilizando un lenguaje en vez de usar esquemas. Sin embargo, se siguieron utilizando esquemas puesto que desde el punto de vista del ser humano son mucho más sencillos de entender, aunque un lenguaje siempre permite una edición más rápida y sencilla. Conforme las herramientas de diseño se volvieron más sofisticadas, y la posibilidad de desarrollar circuitos digitales mediante dispositivos programables era más viable, apareció la necesidad de poder describir los circuitos mediante un lenguaje de alto nivel de abstracción. No desde un punto de vista estructural, sino desde el punto de vista funcional. Este nivel de abstracción se había alcanzado ya con las herramientas de simulación, ya que para poder simular partes de un sistema era necesario disponer de modelos que describieran el funcionamiento de bloques del circuito o de cada componente si fuera necesario. Estos lenguajes estaban sobre todo orientados a la simulación, por lo que poco importaba que el nivel de abstracción fuera tan alto que no fuera sencillo una realización o síntesis a partir de dicho modelo. Con la aparición de técnicas para la síntesis de circuitos a partir de lenguajes de alto nivel de abstracción, se comenzaron a utilizar los lenguajes de simulación para sintetizar circuitos. Que si bien alcanzan un altísimo nivel de abstracción, su orientación era básicamente la de simular, por lo que los resultados de una síntesis a partir de descripciones 4 CAPÍTULO I: LENGUAJES DE DESCRIPCIÓN DE HARDWARE con estos lenguajes no eran siempre las más optimas. Además, los lenguajes de descripción de hardware al formar parte de las herramientas EDA permiten el trabajo en equipo. Así, al estructurar el desarrollo del proyecto, cada integrante del equipo de diseño puede trabajar en subproyectos antes de integrar todas las partes del sistema. • Un circuito hecho mediante una descripción en un HDL puede ser utilizado en cualquier tipo de dispositivo programable capaz de soportar la densidad del diseño. Es decir, no es necesario adecuar el circuito a cada dispositivo porque las herramientas de síntesis se encargan de ello. • Una descripción realizada en un HDL es más fácil de leer y comprender que los netlist o circuitos esquemáticos. 1.3.1 VENTAJAS DE LOS HDLS Una metodología de diseño que utiliza un HDL posee varias ventajas sobre la metodología tradicional de diseño a nivel compuerta. Algunas de estas ventajas son listadas a continuación. • Es posible verificar el funcionamiento del sistema dentro del proceso de diseño sin necesidad de implementar el circuito. • Las simulaciones del diseño, antes de que éste sea implementado mediante compuertas, permiten probar la arquitectura del sistema para tomar decisiones en cuanto a cambios en el diseño. • Las herramientas de síntesis tienen la capacidad de convertir una descripción hecha en un HDL, VHDL por ejemplo, a compuertas lógicas y, además, optimizar dicha descripción de acuerdo a la tecnología utilizada. • Esta metodología elimina el antiguo método tedioso de diseño mediante compuertas, reduce el tiempo de diseño y la cantidad de errores producidos por el armado del circuito. • Las herramientas de síntesis pueden transformar automáticamente un circuito obtenido mediante la síntesis de un código en algún HDL, a un circuito pequeño y rápido. Además, es posible aplicar ciertas características al circuito dentro de la descripción para afinar detalles (retardos, simplificación de compuertas, etc.) en la arquitectura del circuito y que estas características se obtengan en la síntesis de la descripción. • Las descripciones en un HDL proporcionan documentación de la funcionalidad de un diseño independientemente de la tecnología utilizada. IEC FRANCISCO JAVIER TORRES VALLE 1.4 VHDL VHDL es un lenguaje de descripción de hardware utilizado para describir circuitos en un alto nivel de abstracción el cual está siendo rápidamente aceptado como un medio estándar de diseño. VHDL es producto del programa Very High Speed Integrated Circuit (VHSIC) desarrollado por el Departamento de Defensa de los Estados Unidos a finales de la década de los 70's. El propósito era hacer un estándar para diseñar, modelar, y documentar circuitos complejos de tal manera que un diseño desarrollado por una empresa pudiera ser entendido por otra y, además, pudiera ser procesado por software con propósitos de simulación. VHDL es reconocido como un estándar de los lenguajes HDL por el Instituto de Ingenieros en Electricidad y Electrónica – IEEE – como su estándar 1076 el cual fue ratificado en 1987, y por parte del Departamento de Defensa de los Estados Unidos como el estándar MIL-STD-454L En 1993 el estándar IEEE-1076 se actualizó y un estándar adicional, el IEEE-1164, fue adoptado. Para 1996 el estándar IEEE-1076.3 se convirtió en un estándar de VHDL para síntesis siendo éste el que se utiliza en el diseño de sistemas digitales. Los estándares más utilizados en síntesis de circuitos por la mayoría de las herramientas de diseño son el IEEE-1164 y el IEEE-1076.3. En la actualidad VHDL es un estándar de la industria para la descripción, modelado y síntesis de circuitos digitales. Por esto, los ingenieros de la mayoría de las áreas de electrónica, si no es que todas, deben aprender a programar en VHDL para incrementar su eficiencia. VHDL divide los circuitos en dos “vistas” entidades y arquitecturas. La entidad modela al circuito, componente o sistema externamente 5 CAPÍTULO I: LENGUAJES DE DESCRIPCIÓN DE HARDWARE definiendo a este mediante un nombre y sus conexiones que vienen siendo las entradas y salidas del circuito. En tanto que la arquitectura, que es la vista interna, define el funcionamiento del circuito. Después de definir las interfaces de la entidad, otras entidades pueden utilizar a la primera como un subcircuito, al mismo tiempo que todas están siendo desarrolladas, es decir, están siendo detalladas en su funcionamiento. Este concepto de vistas externas e internas es propio de VHDL y permite segmentar un sistema en bloques. Así, una entidad es relativa a otras entidades a través de sus conexiones y comportamiento. Por lo que es posible experimentar cada entidad con diferentes arquitecturas sin necesidad de cambiar el resto del diseño. Y obviamente cada entidad puede ser reutilizada en otros sistemas aunque no hayan sido diseñadas específicamente para estos. Un modelo de hardware de VHDL es mostrado en la siguiente figura. Una señal posee una fuente (driver) y uno más destinos (receptores) y un tipo de dato que le proporciona características de interconexión. Por ejemplo, una señal que se define como tipo bit puede manejar los valores binarios ‘0’ y ‘1’ solamente, en tanto que una señal que se define como bit_vector puede manejar mas de una posición binaria. La forma de diseñar circuitos en VHDL se divide en tres categorías de acuerdo a su complejidad: flujo de datos, comportamental, y estructural. Estos tres estilos de diseño se detallan a continuación. • FLUJO DE DATOS En este estilo el diseño del circuito no es complicado por lo que basta con describir como fluyen los datos través de la entidad, de las entradas hacia las salidas. La operación del sistema está definida en términos de un conjunto de transformaciones de datos expresadas como instrucciones concurrentes. • COMPORTAMENTAL El diseño es un poco más complicado ya que requiere de varias decisiones antes de definir los datos de salida correctos. Por lo que se requiere de una descripción algorítmica del funcionamiento del circuito para facilitar el diseño del sistema. En VHDL esto se obtiene expresando el funcionamiento del diseño mediante una estructura PROCESS la cual se compone de instrucciones secuénciales. Figura 1.2 Modelo de Hardware de VHDL Una entidad en VHDL, que ya es todo un diseño, posee una o más conexiones hacia los sistemas que la rodean. Una entidad puede estar compuesta de otras entidades, de procesos y por componentes, todos ellos trabajando concurrentemente. Cada entidad está definida por su arquitectura la cual se forma de instrucciones en VHDL, ya sean aritméticas, asignaciones a señales o de simples instanciaciones de componentes. Los PROCESS en VHDL son utilizados para modelar tanto circuitos secuénciales como combinacionales utilizando un estilo de descripción secuencial. Para interconectar procesos distintos se utilizan SIGNALS que no son otra cosa que simples cables. IEC FRANCISCO JAVIER TORRES VALLE • ESTRUCTURAL Una descripción estructural se utiliza en circuitos que requieren de más de una función, hablando en términos de hardware, para realizar la finalidad del sistema. Para ello segmentamos el sistema en subcircuitos o componentes para facilitar el diseño. Cada componente es caracterizado en particular ya sea utilizando una descripción de flujo de datos o comportamental. Y a la entidad donde se describen las interconexiones de estos componentes recibe el nombre de descripción estructural. Lo que ha hecho que VHDL sea en un tiempo tan corto el lenguaje de descripción de hardware más utilizado por la industria electrónica, es su independencia con la metodología utilizada por cada diseñador, su capacidad de descripción a diferentes niveles de abstracción, y en definitiva la 6 CAPÍTULO I: LENGUAJES DE DESCRIPCIÓN DE HARDWARE posibilidad de poder reutilizar en diferentes aplicaciones un mismo código. 1.5 I. METODOLOGÍA DE DISEÑO UTILIZANDO VHDL Definición de los requerimientos del sistema. Antes de comenzar a realizar la descripción del diseño, es muy importante que se tenga una idea clara de los objetivos y requerimientos. Tales como: funciones del circuito, máxima frecuencia de operación, y los puntos críticos del sistema. Esto servirá para poder definir a grandes rasgos cual será la arquitectura del circuito y así comenzar a realizar la descripción. II. Descripción del circuito en VHDL. Antes de comenzar a escribir el código es recomendable seleccionar alguna metodología de diseño como: Top-Down, Bottom-Up, o Flat. Los dos primeros involucran la creación de diseños jerárquicos que generalmente son grandes, y el último es utilizado normalmente en el diseño de circuitos pequeños. diagrama a bloques con la descripción del funcionamiento de cada bloque, diagramas de estado, o usar alguna tabla de funcionamiento donde se resumen las funciones de cada bloque en particular. Obviamente existe la posibilidad de cometer errores en VHDL, pero generalmente estos son de son de sintaxis, como ";" al final de cada instrucción, o simplemente por no utilizar adecuadamente alguna instrucción. Algunas ocasiones se podrán tener problemas al tratar de sintetizar el código y esto se debe a que se comete el error de pensar en términos de programación en vez de enfocarnos en la descripción del circuito. Cuando se utiliza VHDL el objetivo principal es el diseño de hardware y para ello debemos de utilizar técnicas de síntesis apropiadas al lenguaje, ya que se suele cometer el error de comenzar a programar en vez de describir y esto provoca que nos olvidemos del objetivo que es el hardware. LA CLAVE PARA DESCRIBIR Y SINTETIZAR FÁCILMENTE CIRCUITOS DIGITALES CON VHDL ES PENSAR EN TÉRMINOS DE COMPUERTAS Y REGISTROS Y NO EN FUNCIÓN DE VARIABLES Y SUBRUTINAS III. Simulación de la descripción en VHDL. La metodología Top-Down consiste en dividir el sistema en varios bloques de tal manera que se puedan resolver los problemas por separado, además, cada bloque a su vez se puede dividir en otros bloques si es necesario. El objetivo es que cada bloque tenga una función especifica representada mediante un componente que desempeñe dicha función. Bottom-Up es todo lo contrario, comenzamos por caracterizar los componentes básicos del circuito y con estos formamos bloques de mayor tamaño que representen un circuito más complejo que sus partes individuales. La metodología Flat es comúnmente utilizada para diseños pequeños, donde los requerimientos son pocos y no muy complejos por lo que no nos distraen y no perdemos de vista la funcionalidad del circuito. Este método de diseño es el que utilizamos cotidianamente en el diseño de circuitos digitales, y se le llama Flat por que no es necesario seccionar el circuito para poder diseñarlo. Síntesis consiste en reducir una descripción realizada en un lenguaje de alto nivel de abstracción a un nivel de compuerta que pueda ser implementada en un circuito. Dicho de otra manera, síntesis es el proceso mediante el cual una descripción es convertida en un listado de conexiones (netlist) entre las compuertas, registros, multiplexores, etc. de un dispositivo lógico programable. Después de decidir cual será la metodología que debemos implementar entonces comenzamos a describir el circuito de acuerdo con lo que se había establecido. Es recomendable utilizar algún tipo de Por ejemplo, una compuerta XOR puede ser sustituido por su equivalente: A XOR B = A'B+AB', o una instrucción IF puede ser en algunas ocasiones una compuerta AND, en otras IEC FRANCISCO JAVIER TORRES VALLE La simulación del código, o simulación funcional, nos permite detectar y corregir errores antes que se implemente en el dispositivo. La modularidad implementada facilita la evaluación del circuito, porque al describir el circuito por bloques podemos analizar cada uno por separado antes de unirlos. Esta simulación equivale a la depuración de programas en los lenguajes de computación. IV. Síntesis 7 CAPÍTULO I: LENGUAJES DE DESCRIPCIÓN DE HARDWARE una OR, o inclusive toda una función booleana que involucra diferentes tipos de compuertas. Por lo que el proceso de síntesis depende del dispositivo utilizado. Generalmente una misma función es implementada de diferentes formas de acuerdo al dispositivo que estemos utilizando y esto no cambia la funcionalidad del diseño y será la misma si se selecciona el componente adecuado a la complejidad del diseño. El proceso utilizado para sintetizar un código en un CPLD es conocido como Fitting o ajuste y consiste en adaptar las ecuaciones booleanas en los diferentes bloques lógicos del dispositivo. Cuando se utiliza un FPGA el proceso empleado se le llama Place And Route y consiste en adecuar las ecuaciones a través de varias celdas lógicas. Aunque la finalidad es la misma, la manera en que se sintetiza un código en un CPLD es totalmente distinta a la síntesis de circuitos utilizando FPGAs. Por otro lado la optimización en la conversión del código VHDL a ecuaciones booleanas depende de tres factores: I. La descripción del circuito. II. Los recursos disponibles en el dispositivo seleccionado. III. Las directivas de síntesis seleccionadas por el diseñador. La descripción es el punto más importante porque de esto dependen los otros dos. En la descripción no solamente tenemos que “decir” como funciona el circuito, además, tenemos que describir en que “forma” debe de hacerlo. No es lo mismo describir el diseño de un sumador de cuatro bits utilizando cuatro módulos que realizan la suma basándose en propagación de bits de acarreo entre estos, a describir un circuito que realice la suma de manera paralela sin utilizar retroalimentaciones. Finalmente suman pero no lo hacen igual. Los recursos afectan la forma en que son implementadas las ecuaciones lógicas en el dispositivo. Por ejemplo, un contador de 4 bits con borrado asíncrono no puede ser implementado en un 16V8, porque el registro de la macrocelda de salida del dispositivo no cuenta con esta característica. Finalmente las directivas de síntesis influyen directamente en el proceso de cálculo de las ecuaciones que son implementadas en el dispositivo. Algunas de estas directivas son: asignación de pines, sintetizar para maximizar velocidad, sintetizar para optimizar área, y algunas IEC FRANCISCO JAVIER TORRES VALLE que son descritas en el mismo código, como por ejemplo forzar a que un nodo no sea simplificado o eliminado y pueda ser retenido a la salida de una macrocelda. Cuando se sintetiza para maximizar la frecuencia generalmente quedan funciones con varios términos e incluso hay términos que se repiten en las ecuaciones de los nodos de salida, pero esto se hace para evitar la retroalimentación. V. Simulación del código sintetizado Aún y cuando la simulación funcional se haya realizado con éxito, debemos volver a evaluar el circuito que realmente quedó sintetizado en el dispositivo. Ya que las sustituciones de funciones, como el caso de la compuerta XOR, dependerán de las características del dispositivo utilizado. Y es posible que ciertas funciones se ejecuten en más tiempo de los esperado y esto altere el funcionamiento del resto del diseño. Simular el código sintetizado en el circuito permite verificar los retrasos de tiempo de un nodo a otro, evaluar la máxima frecuencia de operación del circuito y verificar que éste funcione adecuadamente. En dado caso que el código no pudiera ser sintetizado podemos tratar de mejorar la descripción, es decir, mejorar el diseño tratando de eliminar registros, compuertas, buffers, etc., encontrar algún error en la descripción, cambiar las directivas de síntesis o definitivamente seleccionar otro dispositivo. VI. Programación del dispositivo Después de completar la descripción, la síntesis y la simulación del circuito con éxito, el siguiente paso es generar el archivo que nos permite implementar físicamente nuestro diseño en un dispositivo programable. Todos los programas de VHDL para síntesis generan un archivo con el que podemos programar el dispositivo. Ya sea JEDEC, JTAG, BITSTREAM, etc. de acuerdo al tipo dispositivo y fabricante. 8 CAPÍTULO II: DISPOSITIVOS LÓGICOS PROGRAMABLES II DISPOSITIVOS LÓGICOS PROGRAMABLES IEC FRANCISCO JAVIER TORRES VALLE 9 CAPÍTULO II: DISPOSITIVOS LÓGICOS PROGRAMABLES 2.1 CONCEPTOS FUNDAMENTALES muestran los circuitos básicos para la mayoría de los PLDs. La fabricación de dispositivos de lógica programable se basa en los siguientes dos conceptos. • FUNCIONALIDAD COMPLETA La cual se fundamenta en el hecho de que cualquier función lógica se puede realizar mediante una suma de productos. • CELDAS DE FUNCIONES UNIVERSALES. También denominadas generadores de funciones, son bloques lógicos configurados para procesar cualquier función lógica, similares en su funcionamiento a una memoria. En estas celdas se almacenan los datos de salida del circuito combinacional en vez de implementar físicamente la ecuación booleana. 2.2 DISPOSITIVOS LÓGICOS PROGRAMABLES Un dispositivo lógico programable, o PLD (Programmable Logic Device), es un dispositivo cuyas características pueden ser modificadas y almacenadas mediante programación. El dispositivo programable más simple es el PAL (Programmable Array Logic). El circuito interno de un PAL consiste en una matriz de conexiones, un matriz de compuertas AND y un arreglo de compuertas OR. Una matriz de conexiones es una red de conductores distribuidos en filas y columnas con un fusible en cada punto de intersección, mediante la cual se seleccionan cuales entradas del dispositivo serán conectadas al arreglo AND cuyas salidas son conectadas al arreglo OR y de esta manera obtener una función lógica en forma de suma de productos. La mayoría de los PLDs están formados por una matriz de conexiones, una matriz de compuertas AND, y una matriz de compuertas OR y algunos, además, con registros. Las matrices pueden ser fijas o programables. Con estos recursos se implementan las funciones lógicas deseadas mediante un software especial y un programador de dispositivos. El tipo más sencillo de matriz programable, que data de los años 60, era una matriz de diodos con un fusible en cada punto de intersección de la misma. En la figura 2.1 se IEC FRANCISCO JAVIER TORRES VALLE Figura 2.1 Estructuras comúnmente utilizadas en PLDs 2.2.1 MATRIZ GENÉRICA PROGRAMABLE Una Matriz Genérica Programable, GAL (Generic Array Logic), es una denominación que utilizaba originalmente Lattice Semiconductor y que más tarde se licenció a otros fabricantes. Un GAL en su forma básica es un PLD con una matriz AND reprogramable, una matriz OR fija y una lógica de salida programable mediante una macrocelda. Esta estructura permite implementar cualquier función lógica en forma de suma de productos con un numero de términos definido. En los PLDs no reprogramables la síntesis de las ecuaciones lógicas se realiza mediante la quema de fusibles en cada punto de intersección de los pines de entrada con las compuertas. En un GAL el fusible se reemplaza por una celda CMOS eléctricamente borrable (EECMOS) y mediante programación se activa o desactiva cada celda EECMOS. Una celda activada conecta su correspondiente intersección de fila y columna, y una celda desactivada desconecta dicha intersección. Con esta estructura se puede aplicar cualquier combinación de variables de entrada, o sus complementos, a una compuerta AND para generar cualquier operación producto que se desee. A continuación se muestran las estructuras típicas de un dispositivo GAL y la macrocelda de salida del GAL22V10. 10 CAPÍTULO II: DISPOSITIVOS LÓGICOS PROGRAMABLES Figura 2.2 Estructura típica de un GAL FIGURA 2.3 Macrocelda de un GAL22V10 2.3 CPLD Un CPLD (Complex Programmable Logic Device) extiende el concepto de un PLD a un mayor nivel de integración ya que permite implementar sistemas más eficientes porque utilizan menos espacio, mejoran la confiabilidad en el circuito, y reducen costos. Un CPLD se forma con múltiples bloques lógicos, cada uno similar a un PLD. Los bloques lógicos se comunican entre sí utilizando una matriz programable de interconexiones lo cual hace más eficiente el uso del silicio y conduce a un mejor desempeño. A continuación se explican brevemente las principales características de la arquitectura de un CPLD. 2.3.1 multiplexores. La primera se basa en una matriz de filas y columnas con una celda EECMOS en cada intersección. Al igual que en el GAL esta celda puede ser activada para conectar/desconectar la correspondiente fila y columna. Esta configuración permite una total interconexión entre las entradas y salidas de los bloques lógicos. Sin embargo, estas ventajas provocan que disminuya el desempeño del dispositivo además de aumentar el consumo de energía y el tamaño del componente. En la interconexión mediante multiplexores, existe un multiplexor por cada entrada al bloque lógico. Las vías de interconexión programables son conectadas a las entradas de un numero fijo de multiplexores por cada bloque lógico. Las entradas de selección de estos multiplexores son programadas para permitir que sea seleccionada únicamente una vía de la matriz de interconexiones por cada multiplexor, la cual se propaga hacia el bloque lógico. Cabe mencionar que estos multiplexores no tienen acceso a todas las vías de la matriz por lo que la rutabilidad se incrementa usando multiplexores de mayor tamaño, permitiendo así que cualquier combinación de señales de la matriz de interconexión pueda ser enlazada hacia cualquier bloque lógico. Sin embargo, el uso de grandes multiplexores incrementa el tamaño de dispositivo y reduce su desempeño. MATRIZ DE INTERCONEXIONES PROGRAMABLES La matriz de interconexiones programables, PIM Programmable Interconect Matrix (véase la figura 2.4), permite unir los pines de entrada/salida a las entradas del bloque lógico, o las salidas del bloque lógico a las entradas de otro bloque lógico, o inclusive a las entradas del mismo bloque. La mayoría de los CPLDs usan una de dos configuraciones para esta matriz: interconexión mediante arreglo o interconexión mediante IEC FRANCISCO JAVIER TORRES VALLE Figura 2.4 Arquitectura Básica de un CPLD 2.3.2 BLOQUES LÓGICOS Un bloque lógico es muy similar a un PLD, cada uno de ellos poseen generalmente una matriz de compuertas AND, una matriz de compuertas OR y una configuración para la distribución de los 11 CAPÍTULO II: DISPOSITIVOS LÓGICOS PROGRAMABLES productos en las diferentes macroceldas del boque. El tamaño del bloque lógico es una medida de la capacidad del CPLD, ya que de esto depende el tamaño de la función booleana que pueda ser implementada dentro del bloque. Los bloques lógicos usualmente tienen de cuatro a veinte macroceldas. La cantidad de bloques lógicos que puede poseer un CPLD depende de la familia y fabricante del dispositivo. familia MAX se colocan 4 productos por macrocelda los cuales pueden ser compartidos con otras macroceldas. Cuando un producto puede ser únicamente utilizado por una macrocelda se le conoce como termino - producto dirigido, y cuando estos pueden ser utilizados por otras macroceldas se le llama termino - producto compartido. Mediante estos productos compartidos se mejora la utilización del dispositivo, sin embargo, esto produce un retardo adicional al tener que retroalimentar un producto hacia otra macrocelda y con esto disminuye la velocidad de trabajo del circuito. La forma en que son distribuidos los productos repercute en la flexibilidad que proporciona el dispositivo para el diseñador. Además, que estos esquemas proporcionan también flexibilidad para los algoritmos del programa de síntesis que es el que finalmente selecciona la mejor forma en que deben ser distribuidas las ecuaciones lógicas en el componente. Figura 2.5 Estructura de un Bloque Lógico en dispositivos de las familias MAX340 y MAX5000 2.3.3 DISTRIBUCIÓN DE PRODUCTOS Existen pequeñas diferencias en cuanto a la distribución de los productos en un CPLD, esto dependerá de la familia del dispositivo y del fabricante. Obviamente el tamaño de las sumas sigue siendo el factor más importante para la implementación de funciones lógicas. Pero cada fabricante distribuye los productos de diferente forma. La familia MAX de CPLDs que fue desarrollada por Cypress Semiconductor conjuntamente con Altera Corporation, siendo los primeros en sacar al mercado unan familia de CPLDs, Altera la llamó MAX5000 y Cypress por su parte la clasificó como MAX340, la distribución de productos no es igual a la de un PLD. En un dispositivo como el 22V10 tenemos que la suma de productos es fija por cada macrocelda -8, 10, 12, 14 o 16 productos-, en la IEC FRANCISCO JAVIER TORRES VALLE Figura 2.6 Distribución de Productos en dispositivos de las familias MAX340 y MAX5000 2.3.4 MACROCELDAS Las macroceldas de un CPLD son similares a las de un PLD. Estas también están provistas con registros, control de polaridad, y buffers para utilizar salidas con alta impedancia. Por lo general un CPLD tiene macroceldas de entrada/salida, macroceldas de entrada y macroceldas internas u ocultas (buried macrocells), en tanto que un 22V10 tiene solamente macroceldas de entrada/salida. Una macrocelda interna es similar a una macrocelda de entrada/salida, sólo que esta no puede ser conectada directamente a una terminal del dispositivo. La salida de una macrocelda 12 CAPÍTULO II: DISPOSITIVOS LÓGICOS PROGRAMABLES interna va conectada directamente a la matriz de interconexiones programable. Por lo que es posible manejar ecuaciones y almacenar el valor de salida de estas internamente utilizando los registros de estas macroceldas. En la figura 2.7 se muestran la arquitectura interna de un CPLD de la familia FLASH 370 de Cypress Semiconductors. En esta podemos apreciar las macroceldas de entrada/salida, macroceldas ocultas y celdas de entrada/salida con las que cuenta el dispositivo. Figura 2.7 Macroceldas de entrada/salida, macroceldas ocultas y celdas de entrada/saliad en dispositivos de la familia FLASH 370 Las macroceldas de entrada, como la que se muestra en la figura 2.8, son utilizadas para proporcionar entradas adicionales para las funciones lógicas. En el diagrama se muestra la macrocelda de entrada de la familia FLASH 370. En general las macroceldas de entrada incrementan la eficiencia del dispositivo al ofrecer algunos registros adicionales con los que se pueden almacenar el valor de la terminal de entrada. 2.3.5 En la figura 2.7 se puede apreciar una celda de entrada/salida, que bien podría considerarse parte del bloque lógico, pero no necesariamente tienen que estar a la salida de un bloque lógico. La función de una celda de entrada/salida es permitir el paso de una señal hacia dentro o hacia el exterior del dispositivo. Dependiendo del fabricante y de la arquitectura del CPLD estas celdas son pueden ser consideradas o no parte del bloque lógico. 2.4 Figura 2.8 Macrocelda de entrada en dispositivos de la familia FLASH 370 IEC FRANCISCO JAVIER TORRES VALLE CELDA DE ENTRADA/SALIDA FPGA La arquitectura de un FPGA (Field Programmable Gate Array) consiste en arreglos de varias celdas lógicas las cuales se comunican unas con otras mediante canales de conexión verticales 13 CAPÍTULO II: DISPOSITIVOS LÓGICOS PROGRAMABLES y horizontales tal y como se muestra en la figura 2.9. éste es programado ya no se puede recuperar. La diferencia radica en que en un fusible normal se desactiva deshabilitando la conexión, en tanto que en estos anti - fusibles cuando son programados se produce una conexión por lo que normalmente se encuentran abiertos. La desventaja obvia es que no son reutilizables, pero por el contrario disminuyen considerablemente el tamaño y costo de los dispositivos. • Figura 2.9 Arquitectura básica de un FPGA 2.4.1 CELDAS LÓGICAS Cada celda lógica es funcionalmente similar a los bloques lógicos de un CPLD. La diferencia está en que un FPGA normalmente utiliza generadores de funciones en vez de compuertas. Cada uno de estos generadores es como una memoria en donde en vez de implementar la función lógica mediante compuertas, se precalcula el resultado y se almacena en el generador. Las entradas al generador funcionan como un bus de direcciones, y mediante las diferentes combinaciones de las entradas al generador se selecciona el resultado correcto. Esto le da una gran densidad al dispositivo ya que se maneja un gran número de generadores, pero el tiempo de propagación al implementar una función lógica en estos generadores es menor al que se necesitaría si utilizáramos compuertas. La estructura de las celdas lógicas y las formas en que estas pueden ser interconectadas, tanto salidas como entradas de la celda, varían de acuerdo al fabricante. En general una celda lógica tiene menos funcionalidad que la combinación de sumas de productos y macroceldas de un CPLD, pero como cada FPGA tienen una gran cantidad de celdas lógicas es posible implementar grandes funciones utilizando varias celdas lógicas en cascada. Además de las celdas lógicas también es importante la tecnología utilizada para crear las conexiones entre los canales, las más importantes son las siguientes. • ANTIFUSE Al igual que la tecnología PROM, un FPGA que utiliza este tipo de tecnología sólo se puede programar una sola vez y utilizan algo similar a un fusible para realizar las conexiones. Una vez que IEC FRANCISCO JAVIER TORRES VALLE SRAM Las celdas SRAM son implementadas como generadores de funciones para remplazar la lógica combinacional mediante compuertas y, además, son usadas para controlar multiplexores e interconectar las celdas lógicas entre ellas. En estas el contenido se almacena mediante un proceso de configuración en el momento de encendido del circuito que contiene al FPGA. Ya que al ser SRAM, el contenido de estos bloques de memoria se pierde cuando se deja de suministrar la energía. La información binaria de las celdas SRAM generalmente se almacena en memorias seriales EEPROM conocidas como memorias de configuración. En el momento de encendido del circuito toda la información binaria es transferida a las celdas del FPGA mediante el proceso de configuración el cual es generalmente automático y el propio FPGA contiene un circuito interno que se encarga de hacer todo el proceso. Un FPGA que tiene una gran cantidad de canales de interconexión tiende a tener pequeñas celdas lógicas con muchas entradas y salidas en comparación con el número de compuertas que tiene la celda, este tipo de FPGAs generalmente utilizan tecnología ANTIFUSE. Un FPGA que tiene una estructura pequeña en canales de interconexión tiende a tener grandes celdas lógicas con pocas entradas y salidas en comparación con el número de compuertas que hay en la celda. Este tipo de FPGA generalmente está fabricado con tecnología SRAM. Una arquitectura con celdas lógicas pequeñas permite utilizar todos los recursos del dispositivo. Sin embargo, si las celdas lógicas son muy pequeñas entonces tendremos que utilizar un gran número de estas para poder implementar funciones lógicas de varios términos, lo cual agrega un tiempo de retardo por cada celda lógica implementada. Cuando el tamaño de la celda lógica es grande sucede lo contrario, en este tipo de celdas lógicas es posible utilizar un gran número de compuertas por lo que podemos 14 CAPÍTULO II: DISPOSITIVOS LÓGICOS PROGRAMABLES implementar funciones lógicas de varios términos con pocas celdas lógicas. El que el tamaño de la celda sea grande no afecta la frecuencia máxima de trabajo porque estamos hablando de que existe un gran numero de compuertas que pueden ser usadas en la función paralelamente, siendo el mismo tiempo de retardo para todas. Sin embargo, cuando las funciones son pequeñas en comparación con el tamaño de la celda no es necesario utilizar todas las compuertas de la celda, por lo que este tipo de celdas no son precisamente las más indicadas para desempeñar pequeñas funciones. La tecnología SRAM es utilizada por Altera, Lucent Technologies, Atmel, Xilinx y otros. La tecnología ANTIFUSE es utilizada por Cypress, Actel, QuickLogic, y Xilinx. A continuación se muestran algunas celdas lógicas de distintos fabricantes. Figura 2.10 Bloque Lógico Configurable de la familia XC4000 de Xilinx, Inc. IEC FRANCISCO JAVIER TORRES VALLE 15 CAPÍTULO II: DISPOSITIVOS LÓGICOS PROGRAMABLES Figura 2.11 Elemento Lógico de la familia APEX20K de Altera Corporation Figura 2.12Modulo Lógico de la familia ACT3 de Actel Corporation IEC FRANCISCO JAVIER TORRES VALLE 16 CAPÍTULO III: SINTAXIS DEL LENGUAJE III IEC FRANCISCO JAVIER TORRES VALLE SINTAXIS DEL LENGUAJE 17 CAPÍTULO III: SINTAXIS DEL LENGUAJE 3.1 INTRODUCCIÓN A LA DESCRIPCIÓN EN VHDL DE CIRCUITOS DIGITALES En este capítulo se discutirán los elementos fundamentales de VHDL que son comúnmente utilizados en síntesis de circuitos. Primero se exponen el diseño de multiplexores y comparadores con VHDL para hacer una analogía con la metodología convencional de diseño. Ya que es muy importante comprender porque VHDL es un lenguaje para describir y no para programar. Posteriormente se expondrán los elementos básicos del lenguaje, tales como: identificadores, objetos de datos, tipos de datos, operadores y tipos de instrucciones. 3.1.1 z0 1 1 1 Utilizando cualquier técnica de simplificación de ecuaciones obtenemos: z0 = s0’·x0+s0·x1. Y el circuito quedaría como se muestra en la figura 3.2. Figura 3.2 Circuito del Multiplexor 2 a 1 MULTIPLEXORES Antes de examinar la descripción en VHDL de multiplexores, analizaremos el funcionamiento interno y la metodología tradicional de diseño utilizada en este tipo de circuitos para después realizar la descripción del circuito en VHDL. En la figura 3.1 se describe externamente a un multiplexor y la tabla resume su funcionalidad. x0 x1 1 ENTRADA SALIDA s0 z0 0 x0 1 x1 s0 Figura 3.1 Multiplexor 2 a 1 La tabla de verdad completa sería la siguiente. ENTRADAS SALIDA s0 x0 x1 z0 0 0 0 0 0 0 1 0 0 1 0 1 0 1 1 1 1 0 0 0 1 0 1 1 1 1 0 0 IEC FRANCISCO JAVIER TORRES VALLE En VHDL podemos describir el circuito ya sea mediante la descripción completa de todas las combinaciones de las entradas, utilizando la tabla simplificada de funcionamiento o si lo deseamos es posible realizar la descripción compuerta por compuerta del circuito. Al primer estilo se le conoce como de flujo de datos y en este debemos describir como fluyen los datos de entrada hacia la salida. A continuación se muestra la descripción de flujo de datos del multiplexor con VHDL utilizando la tabla completa de funcionamiento del mismo. Las palabras en negritas son palabras reservadas en VHDL y los comentarios comienzan con dos guiones (--). ENTITY multiplexor IS PORT (s0, x0, x1: IN bit; z0: OUT bit); END multiplexor; ARCHITECTURE data_flow OF multiplexor IS SIGNAL temp: bit_vector (2 DOWNTO 0); BEGIN z0 <= '0' WHEN temp = "000" ELSE '0' WHEN temp = "001" ELSE '1' WHEN temp = "010" ELSE '1' WHEN temp = "011" ELSE '0' WHEN temp = "100" ELSE '1' WHEN temp = "101" ELSE '0' WHEN temp = "110" ELSE '1'; temp <= s0 & x0 & x1; -- Concatenación -- de las entradas en un -- solo bus. END data_flow; Las descripciones en VHDL son creadas a partir de dos estructuras que son fundamentales 18 CAPÍTULO III: SINTAXIS DEL LENGUAJE para el lenguaje: la entidad y la arquitectura. Básicamente la entidad es la estructura en la que se define cuales son las entradas y salidas del circuito que deseamos representar, la cual podemos asociar con una “caja” en la que se que precisan cuales son las interfaces de comunicación con el exterior, siendo la arquitectura donde se detalla el comportamiento interno de esa “caja”. Observe que en la descripción anterior se utilizó un objeto de datos llamado SIGNAL para crear el bus “temp” y concatenar “s0”, “x0” y “x1” en un solo objeto y así facilitar la descripción. A continuación utilizaremos la tabla simplificada para diseñar el multiplexor, ya que si observamos la salida depende fundamentalmente de la entrada de selección “s0”, por lo que atendiendo a esta característica la descripción de flujo de datos quedaría tal y como se muestra a continuación. ENTITY multiplexor IS PORT (s0, x0, x1: IN bit; z0: OUT bit); END multiplexor; ARCHITECTURE data_flow OF multiplexor IS BEGIN z0 <= x0 WHEN s0 = '0' ELSE x1; END data_flow; En ambas descripciones hemos definido el funcionamiento de la salida apoyándonos en las entradas. Note que existe cierto “paralelismo” de las entradas hacia las salidas, es decir, no importa cual combinación de entradas se dé, sólo una opción será asignada a la salida. Por lo que no importa cual orden se haya seguido en la descripción del circuito. Y esta es una de las principales características de VHDL, es decir, no importa tanto el orden de las instrucciones, lo cual no es así en lenguaje de programación de software. Tal vez este “paralelismo” se perciba con mayor detalle realizando la descripción del circuito compuerta por compuerta utilizando la ecuación simplificada del circuito obtenida anteriormente. not_s0 <= NOT s0; and2 <= s0 AND x1; END data_flow; La descripción anterior también es de flujo de datos y no sigue ningún orden en particular en el uso de las instrucciones y esto se ha hecho para destacar el comportamiento paralelo o concurrente de VHDL. Observe que cada ecuación describe a cada una de las compuertas que se muestran en la figura 3.2, por lo cual no hubiera importado el orden que hayamos seguido siempre y cuando se realicen las conexiones correctamente. Pensemos en el circuito implementado físicamente en el laboratorio. Cada una de estas compuertas posee características eléctricas que les asignan un funcionamiento definido. Estas particularidades eléctricas cumplen con leyes físicas que se están cumpliendo todo momento y, entonces, no importa como se hayan ordenado los circuitos entre sí lo importante es realizar correctamente las conexiones para obtener la función deseada. En VHDL se trata de emular ese comportamiento, por lo tanto el orden que se haya seguido en cada una de las instrucciones anteriores no es importante, ya que hicimos correctamente la interconexión entre las compuertas. 3.1.2 COMPARADORES La figura 3.3 representa a un comparador y la siguiente tabla resume su funcionalidad. ENTRADAS SALIDAS x_may_y equals x_men_y x>y 1 0 0 x=y 0 1 0 x<y 0 0 1 ENTITY multiplexor IS PORT (s0, x0, x1: IN bit; z0: OUT bit); END multiplexor; ARCHITECTURE data_flow OF multiplexor IS SIGNAL not_s0, and1, and2: bit; BEGIN z0 <= and1 OR and2; and1 <= not_s0 AND x0; IEC FRANCISCO JAVIER TORRES VALLE 19 CAPÍTULO III: SINTAXIS DEL LENGUAJE Figura 3.3 Comparador En el diseño convencional de un comparador tendríamos que realizar una tabla de todos los posibles valores lógicos de las salidas respecto a las entradas. Lo cual en este caso sería de 256 combinaciones, dado que tenemos ocho bits de entrada para obtener las tres ecuaciones de salida. En VHDL basta con describir de una forma general el funcionamiento del hardware y el sintetizador se encargará de generar toda esta tabla de 256 combinaciones y obtener las ecuaciones lógicas de las tres salidas. El código mostrado a continuación corresponde al comparador mostrado en la figura 3.3. ENTITY comparador IS PORT ( x: IN bit_vector (3 DOWNTO 0); y: IN bit_vector (3 DOWNTO 0); equals: OUT bit; x_may_y: OUT bit; x_men_y: OUT bit); END comparador; ARCHITECTURE data_flow OF comparador IS BEGIN equals <= '1' WHEN x = y ELSE '0'; x_may_y <= '1' WHEN x > y ELSE '0'; x_men_y <= '1' WHEN x < y ELSE '0'; END data_flow; Nótese que en la primera declaración de puertos, dentro de la entidad del comparador, se definen dos bus de entrada de cuatro bits de magnitud (x, y), en cambio las salidas son de solamente un bit. En la entidad lo único que hacemos es describir como es el circuito, o aquello del circuito que permite a la entidad comunicarse hacia otras entidades, sin mencionar para nada su comportamiento interno. Y es en la arquitectura, después del BEGIN, es donde se realiza la descripción del comportamiento del circuito atendiendo únicamente a la funcionalidad del mismo, es decir, no es necesario analizar cada caso en particular de las 256 posibles combinaciones. 3.1.3 EL ESTILO DE “PROGRAMACIÓN” EN VHDL Haciendo una comparación con un lenguaje de programación de alto nivel podemos ver que el código es similar en cuanto a las sentencias utilizadas, sin embargo, no es así en el flujo de ejecución de las instrucciones. Un código de programación en VHDL no es precisamente un IEC FRANCISCO JAVIER TORRES VALLE “programa”, ya que un programa es un conjunto de instrucciones que se ejecutan paso a paso para llevar a cabo una tarea determinada, y en este caso no podemos decir que las instrucciones se estén ejecutando de esta manera, porque esto no corresponde en la realidad al comportamiento de un circuito. En VHDL las instrucciones se están ejecutando en todo momento lo cual sí se asemeja al comportamiento real de un circuito. Así cuando cambie alguna señal de entrada cambiará inmediatamente la salida y, por consiguiente, estamos describiendo cual es el verdadero funcionamiento del circuito. La forma en que se “programa” en VHDL al principio resultará un tanto extraña, pero si asociamos éste código con el circuito que estamos describiendo, podemos darnos cuenta que en él los componentes siempre están activos, y es esto es precisamente lo que describimos mediante VHDL. Tal vez alguna vez ha utilizado PSPICE o algún programa de entrada esquemática de diseño para modelar y simular circuitos, estos también son para la descripción de circuitos. En PSPICE la descripción se realiza mediante un listado de conexiones (netlist) entre los componentes, en tanto que en los otros lo hacemos de manera gráfica y en ambos se considera que todos los componentes siempre están funcionando para que la simulación o modelado del diseño sea de acuerdo a la realidad. Por esto en VHDL el orden de las instrucciones no es tan importante como en el caso de un lenguaje de programación de software, porque las instrucciones se están ejecutando al mismo tiempo y así sí se modela adecuadamente un circuito. Posteriormente se explicarán los tipos de instrucciones y sus diferencias, ya que VHDL si permite la “descripción secuencial” utilizando instrucciones de esta naturaleza dentro de una estructura llamada PROCESS. En esta estructura las instrucciones se ejecutan “paso a paso” como en los lenguajes de programación de software. Pero de cualquier manera esta estructura siempre esta activa, como si fuera un componente o subcircuito del diseño, por lo que todo lo que se obtenga dentro del proceso se ejecutará paralelamente con el resto de las instrucciones que están fuera de esta estructura. Otro punto importante es el dispositivo lógico programable que estemos utilizando, ya que si éste no tiene la capacidad para realizar lo que “dice” nuestra descripción nunca podremos 20 CAPÍTULO III: SINTAXIS DEL LENGUAJE sintetizar el código. Por ejemplo, si en el dispositivo que usemos no es posible que las salidas puedan ser programadas para que trabajen con alta impedancia, aún y cuando la descripción sea correcta nunca podremos sintetizarla en el dispositivo. EJEMPLOS -- Este es un comentario. ENTITY contador IS -- comentario al final -- de una línea Al principio generalmente se comete el error de tratar de “programar” como si fuera C++, Pascal, Visual Basic o cualquier otro lenguaje de programación de software, además de olvidar que el PLD, CPLD, o FPGA que utilicemos tiene características propias que deben ser consideradas cuando se hace la descripción. Pero basta con recordar que estamos diseñando hardware y que por lo tanto no se trata de un lenguaje secuencial de programación para software. Los siguientes ejemplos son de identificadores válidos en VHDL. 3.2 3er_Modulo IDENTIFICADORES Un identificador se define como un conjunto de caracteres con el cual podemos representar diferentes elementos dentro de una descripción. En VHDL un identificador está compuesto por una secuencia de uno o más caracteres alfabéticos, numéricos, o del carácter de subrayado. Las condiciones que debe de seguir un identificador son las siguientes: • VHDL permite la utilización de las letras mayúsculas (A.. Z), minúsculas (a.... z), dígitos (0...9), y el carácter de subrayado (_). • El primer carácter de un identificador debe ser una letra. • El ultimo carácter de identificador no puede ser el carácter de subrayado. Además, el carácter de subrayado no puede aparecer dos o más veces consecutivas. • Mayúsculas y minúsculas son consideradas idénticas. Así, Signal_A, signal_a, y SIGNAL_A se refieren al mismo identificador. • Los comentarios en VHDL comienzan con dos guiones consecutivos (--), y se extienden hasta el final de la línea. Los comentarios pueden aparecer en cualquier lugar dentro de una descripción en VHDL. • VHDL define un grupo de palabras reservadas, llamadas "palabras clave" (keywords), las cuales no pueden ser usadas como identificadores. IEC FRANCISCO JAVIER TORRES VALLE Mi_entidad Mux4a2 TTL_7490 A continuación se muestran ejemplos de identificadores no válidos en VHDL. -- un identificador no -- puede iniciar con un -- dígito _salida_x -- o con el carácter de -- subrayado M__24xmax -- no se permiten dos -- caracteres de -- subrayado seguidos My_design_ -- un identificador no -- debe terminar con un -- carácter de subrayado Unidad& SIGNAL 3.3 -- el caracter "&", no -- es un carácter válido -- palabra reservada OBJETOS DE DATOS Un objeto de datos en VHDL es un elemento que toma un valor de algún tipo de dato determinado. Según sea este tipo de dato, el objeto poseerá un conjunto de propiedades que se le podrán aplicar, como las operaciones en las que el objeto puede ser usado. En VHDL los objetos de datos son generalmente de una de tres clases: constantes, variables o señales. 3.3.1 CONSTANTES Una constante es un elemento que puede tomar un único valor de un tipo dado. A las constantes se les debe asignar un valor en el momento de la declaración. Una vez que se le ha asignado algún valor, éste no puede ser cambiado dentro de la descripción del diseño. Las constantes pueden ser 21 CAPÍTULO III: SINTAXIS DEL LENGUAJE declaradas dentro de las entidades, arquitecturas, procesos o paquetes. Las constantes que se declaren en un paquete pueden ser utilizadas en cualquier descripción en la que se este utilizando dicho paquete. Por otra parte las constantes declaradas dentro de una entidad pueden ser utilizadas por la o las arquitecturas en las que se este haciendo la descripción de dicha entidad, y aquellas constantes que sean declaradas dentro de una arquitectura o proceso, son válidas únicamente dentro de la estructura correspondiente. DECLARACIÓN DE CONSTANTES representan elementos de memoria o conexiones y si pueden ser sintetizadas. Los puertos de una entidad son implícitamente declarados como señales en el momento de la declaración, ya que estos representan conexiones. También pueden ser declaradas en las arquitecturas antes del BEGIN, lo cual nos permite realizar conexiones entre diferentes estructuras de programación. La asignación de valores a un objeto de datos del tipo señal no es inmediata como en el caso de las variables, esto se explicará más detalladamente cuando se exponga la estructura PROCESS y los tipos de instrucciones. CONSTANT identificador: tipo := valor; EJEMPLO DECLARACIÓN DE SEÑALES SIGNAL identificador: tipo [:=valor]; CONSTANT byte: integer := 8; 3.3.2 VARIABLES Los objetos de datos de la clase variable son similares a las constantes, con la diferencia que su valor puede ser modificado cuando sea necesario. Las variables en VHDL son similares a cualquier tipo de variable de un lenguaje de programación de alto nivel. A las variables también se les puede asignar un valor inicial al momento de ser declaradas. Se utilizan únicamente en los procesos y subprogramas (funciones y procedimientos). Las variables generalmente se utilizan como índices, principalmente en instrucciones de bucle, o para tomar valores que permitan modelar componentes. Las variables no representan conexiones o estados de memoria. DECLARACIÓN DE VARIABLES VARIABLE identificador: tipo [:=valor]; EJEMPLO EJEMPLOS SIGNAL A, B: bit := '0'; -- el valor -- inicial es -- opcional SIGNAL dato: bit_vector (7 DOWNTO 0); 3.3.4 ALIAS Un ALIAS no es precisamente un objeto de datos. La instrucción ALIAS permite que utilicemos un identificador diferente para hacer referencia a un objeto de datos, o a parte de él, ya existente. Este no es un objeto de datos nuevo, sino que nos permite manipular fragmentos del objeto de datos original para facilitar la programación. Al modificar el ALIAS se modifica el objeto de datos al que señala. DECLARACIÓN DE ALIAS ALIAS identif: tipo IS identif2 <rango>; VARIABLE aux1, aux2: bit; EJEMPLO 3.3.3 ALIAS instr: bit_vector (3 DOWNTO 0) IS dato (7 DOWNTO 4); SEÑALES Un objeto de la clase señal es similar a un objeto de la clase variable, con una importante diferencia: las señales si pueden almacenar o pasar valores lógicos, mientras que una variable no lo puede hacer. Las señales, por lo tanto, IEC FRANCISCO JAVIER TORRES VALLE 3.4 TIPOS DE DATOS Un tipo de dato especifica el grupo de valores que un objeto de datos puede tomar así como las operaciones que son permitidas con esos valores. En VHDL es sumamente importante el tipo de 22 CAPÍTULO III: SINTAXIS DEL LENGUAJE dato, los objetos de datos no pueden tomar o no se les puede asignar un objeto de datos de otro tipo, y no todas las operaciones se pueden utilizar con los diferentes tipos de datos a menos que se utilicen las librerías adecuadas en las que estén definidas funciones para la conversión de tipos. Además, es posible que el usuario defina subtipos y tipos compuestos, modificando los tipos básicos, así como definir tipos particulares con combinaciones de los diferentes tipos. A continuación se discutirán las dos categorías de tipos de datos más utilizadas en síntesis: escalares y compuestos. 3.4.1 TIPOS ESCALARES Los tipos escalares tienen un orden especifico lo cual permite que sean usados con diferentes operadores. Existen cuatro clases de tipos escalares: enteros, reales o de punto flotante, enumerados, y físicos. • ENTERO VHDL permite especificar la gama del entero (integer) de manera diferente. Sin embargo, la gama debe extender desde por lo menos -(2^31-1) a +(2^31-1), o - 2147483648 a +2147483647. Una señal o variable declarada como tipo entero y que tenga que ser sintetizada en elementos lógicos, debe ser limitada con un rango. EJEMPLO VARIABLE n: integer RANGE -15 TO 15; • REAL El rango de valores que puede tomar este tipo de dato se encuentra entre -1.038E38 a +1.038E38. El Real rara vez es usado en síntesis y en la gran mayoría de las herramientas de software de VHDL para síntesis no es posible utilizar este tipo de dato. • ENUMERADOS Un tipo enumerado es un tipo de dato con un grupo de posibles valores asignados por el usuario. Los tipos enumerados se utilizan principalmente en el diseño de maquinas de estado. TYPE nombre IS ( valor [,valor...] ); El orden en el que los valores son listados en la declaración del tipo enumerado define el orden léxico para ese tipo. EJEMPLOS a) En este ejemplo se define un tipo enumerado llamado “arith”, y los posibles valores son add, sub, mul, y div. TYPE arith IS (add, sub, mul, div); b) Ahora se define un tipo enumerado llamado “estados”, con 4 posibles valores: estado0, estado1, estado2 y estado3. TYPE estados IS ( estado0, estado1, estado2, estado3 ); Existen varios tipos de datos enumerados, algunos predefinidos en los programas de síntesis, para el lenguaje pero generalmente los siguientes tipos enumerados son los más comúnmente utilizados para síntesis de circuitos. BOOLEAN El tipo BOLEAN es un tipo enumerado con dos valores, FALSE y TRUE, donde FALSE < TRUE. Las funciones lógicas y de comparación retornan siempre un valor booleano. Cuando en una operación lógica o de comparación se utilza un tipo de dato no booleano, el bit por ejemplo, existen funciones de conversión que permiten realizar dichas operaciones con distintos tipos de datos. En el caso del bit se utiliza la siguiente función. boolean_var := (bit_var = '1'); BIT El bit es un tipo enumerado que representa valores binarios: '0' y '1'. Las operaciones lógicas en las participa este tipo de dato regresan valores binarios mediante las siguiente función. IF (boolean_var) THEN bit_var := '1'; ELSE bit_var := '0'; END IF; DECLARACIÓN DE UN TIPO ENUMERADO IEC FRANCISCO JAVIER TORRES VALLE 23 CAPÍTULO III: SINTAXIS DEL LENGUAJE CHARACTER El tipo character es un tipo enumerado que contiene el conjunto de los símbolos contenido en el ASCII. STD_LOGIC El tipo std_logic es similar al tipo bit pero con la excepción que éste no esta definido dentro del lenguaje. El paquete std_logic_1164 de la IEEE define al std_logic como un tipo de dato el cual puede tomar los valores 'U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-'. Para poder utilizar este tipo de dato es necesario incluir el paquete dentro de la descripción utilizando las siguientes dos líneas antes de la declaración de la entidad. LIBRARY ieee; USE ieee.std_logic_1164.ALL; TYPE color is (red, green, yellow, blue, violet); TYPE primary_color IS (red, yellow, blue); . . . SIGNAL A: color; SIGNAL B: primary_color; SIGNAL C: bit; SINAL D: std_logic; . . . A <= color'(red); ----- B <= blue; -- Posiblemente el -- programa de síntesis -- marque error en este -- caso C <= '1'; El significado de los valores del std_logic se muestra en la siguiente tabla. 'U' -- Uninitialized 'W' -- Weak Unknow 'X' -- Forcing 'L' -- Weak 0 '0' -- Forcing 0 'H' -- Weak 1 '1' -- Forcing 1 '-' -- Don't care 'Z' -- High Impedance Los valores '0', '1', 'L' y 'H', se utilizan en síntesis de circuitos, los valores 'Z' y '-' tienen restricciones sobre como y donde pueden ser usados. Los valores 'U', 'W' y 'X' se utilizan únicamente para simulación y evaluación de diseños mas no para síntesis. Para la mayoría de los diseños se utiliza este tipo de dato ya que es más completo que el tipo bit por proporcionar los valores 'Z' y '-'. SOBRECARGA DE UN TIPO ENUMERADO Es posible cargar el valor de algún tipo enumerado incluyendo dicho valor en la definición de dos o más tipos enumerados. Cuando se utilice en una descripción dos o más tipos que usen el mismo valor generalmente el programa de síntesis identifica de cual tipo proviene, pero bajo ciertas condiciones esta determinación es imposible. En estos casos es necesario indicar explícitamente de cual tipo se trata. En el siguiente ejemplo se muestra como realizar esta indicación explicita. IEC FRANCISCO JAVIER TORRES VALLE Se indica a que tipo estamos haciendo referencia D <= '1'; -- En estas dos -- asignaciones el -- programa de síntesis -- identifica de que -- tipo se trata CODIFICACIÓN DE LOS TIPOS ENUMERADOS Los tipos enumerados se ordenan de acuerdo a sus valores. Los programas de síntesis automáticamente codifican binariamente los valores del tipo enumerado para que estos puedan ser sintetizados. Algunos programas los hacen mediante una secuencia binaria ascendente, otros buscan cual es la codificación que mejor conviene para tratar de minimizar el circuito o para incrementar la velocidad del mismo una vez que la descripción es sintetizada. También es posible asignar el tipo de codificación mediante directivas de síntesis. El siguiente ejemplo muestra la forma en que el programa de síntesis Foundation de Xilinx, Inc. codifica un tipo enumerado de cinco posibles valores. TYPE color IS (red, green, yellow, blue, violet); La codificación sería la siguiente: red="000", green="001", yellow="010", blue="011", violet="100". Para realizar la codificación manualmente se deben utilizar directivas de síntesis que son propias de cada programa. Para ver ejemplo de cómo se utilizan consulte la ayuda del programa y 24 CAPÍTULO III: SINTAXIS DEL LENGUAJE busque la sección de "directivas de síntesis" o "codificación de tipos enumerados". • FÍSICOS Los tipos físicos son usados para especificar unidades de medida, ya sea de tiempo o para determinar medidas eléctricas. El único tipo predefinido es el “time”, mediante el cual se pueden establecer medidas para simular los retardos de tiempo o para generar diferentes señales que nos permitan simular nuestro diseño. La unidad básica del tipo time es el femtosegundo, y de éste se forman diferente múltiplos. TYPE time IS RANGE -2147483647 TO 2147483647 UNITS fs; ps = 1000 fs; ns = 1000 ps; us = 1000 ns; ms = 1000 us; sec = 1000 ms; min = 60 sec; hr = 60 min; END UNITS; Los tipos físicos no tienen ningún significado en síntesis, sólo son utilizados para simulación de circuitos. IEC FRANCISCO JAVIER TORRES VALLE 25 CAPÍTULO III: SINTAXIS DEL LENGUAJE VARIABLE valor_actual: valores; 3.4.2 TIPOS COMPUESTOS Un tipo compuesto es un tipo de dato formado con elementos de otros tipos. Existen dos formas de tipos compuestos: ARRAYS y RECORDS. Algunas posibles maneras de asignar valores a elementos de estos objetos son: mensaje1(0) <= '1'; -- asignación de valor -- al elemento '0' de -- mensaje1 DECLARACIÓN DEL TIPO ARRAY TYPE nombre IS ARRAY ( rango ) OF tipo; mensaje(5) <= '0'; -- asignación de valor -- al quinto elemento de -- mensaje1 DECLARACION DEL TIPO RECORD TYPE nombre IS RECORD elemento: tipo_de_dato; [;elemento: tipo_de_dato...]; END RECORD; Un ARRAY es un objeto de datos que consiste en una “colección” de elementos del mismo tipo. Los arreglos pueden ser de una o más dimensiones. Los elementos individuales de un arreglo pueden ser utilizados especificando un valor dentro del arreglo. Elementos múltiples de un arreglo pueden ser utilizados especificando más valores. Un RECORD es un objeto de datos que consiste en una “colección” de elementos de diferentes tipos. La estructura RECORD en VHDL es análoga a los RECORDS utilizados en Pascal o a las estructuras en C. Los campos individuales de un RECORD pueden ser utilizados usando los nombres de los elementos. También se puede utilizar más de un campo. EJEMPLOS Las siguientes líneas corresponden a la declaraciones de un tipo ARRAY. TYPE word IS ARRAY (0 TO 15) OF std_logic; TYPE matriz IS ARRAY (0 TO 13, 0 TO 18) OF std_logic; TYPE valores IS ARRAY (0 TO 127) OF integer; A continuación se muestra como declarar objetos de datos utilizando estos tipos. SIGNAL mensaje1, mensaje2: word; SIGNAL arreglo_matriz: matriz; IEC FRANCISCO JAVIER TORRES VALLE mensaje2 <= mensaje1; -- hace mensaje1 -- igual a mensaje2, -- esto es permitido -- ya que se trata de -- dos objetos de datos -- del mismo tipo mensaje2 (63) <= arreglo_matriz (5, 13); -- transfiere el valor -- de un elemento de -- arreglo_matriz a un -- elemento de mensaje2, -- noté que ambos son -- arreglos del tipo -- std_logic_vector A continuación se muestra un ejemplo de una declaración del tipo RECORD. TYPE operacion IS (add, sub, mul, div); TYPE instruccion IS RECORD operador: operacion; op1: integer; op2: integer; END RECORD; Aquí está la declaración de dos objetos usando la declaración del tipo RECORD anterior. VARIABLE inst1, inst2: instruccion; A continuación se muestran algunas posibles maneras de asignar valores a elementos de estos objetos de datos. inst1.operador := add; -- asigna un valor -- a "operador"del -- RECORD inst1 inst2.operador := sub; -- asigna un valor -- a "operador" de -- inst2 inst1.op1 := inst2.op2; 26 CAPÍTULO III: SINTAXIS DEL LENGUAJE inst2 := inst1; ARREGLOS RESTRINGIDOS y1 <= B"1011"; x2 <= x"A"; y2 <= x"7"; z_octal <= o"2"; un_bit <= '1'; Un arreglo restringido (Constrained Array) es aquel que está explícitamente definido mediante rango entero especifico de un tipo de datos ya existente. Cuando se declara un objeto de datos con arreglo restringido, el objeto posee el mismo rango. El tipo std_logic_vector al igual que el bit_vector es simplemente un arreglo de elementos del tipo std_logic. La forma de utilizarlo es similar a la del bit_vector. EJEMPLO: SIGNED & UNSIGNED TYPE byte IS ARRAY (7 DOWNTO 0) OF bit; -- Este es un arreglo restringido cuyo -- rango es: (7, 6, 5, 4, 3, 2, 1, 0) ARREGLOS INDEFINIDOS Un arreglo indefinido o sin restricciones (Unconstrained Array) es aquel que no está delimitado mediante un rango entero especifico. Un objeto de datos declarado con arreglo indefinido deberá ser delimitado o de lo contrario no podrá ser sintetizado. EJEMPLO TYPE bit_vector IS ARRAY (integer RANGE <>) OF bit; VARIABLE v: bit_vector(5 DOWNTO -5); A continuación se exponen algunos tipos compuestos comúnmente utilizados en síntesis de circuitos utilizando VHDL. BIT_VECTOR Los valores asignados al tipo bit_vector deben ser especificados con comillas dobles (" ") y los valores asignados al tipo bit simple son asignados con comillas simples (' '). El prefijo 'X' o 'x' denota un valor hexadecimal; los prefijos 'O' y 'o' denotan un valor octal; el prefijo 'B' o 'b' denota un valor binario. Si ningún prefijo es especificado, se asume el prefijo binario. Las asignaciones en hexadecimal y octal deben usarse únicamente si el valor puede combinarse directamente con el tamaño del vector. Por ejemplo, sí 'a' es un bit_vector ( 0 TO 6 ), entonces la asignación a <= x"B", no podrá hacerse porque el numero hexadecimal 'B' usa cuatro de bits y no equipara el tamaño del vector al que está siendo asignado. STD_LOGIC_VECTOR El estándar 1076.3 de la IEEE es un paquete para VHDL en el cual se definen nuevos tipos de datos además de funciones aritméticas y lógicas para ser utilizadas por herramientas de síntesis. Éste define dos paquetes: el numeric_std y el numeric_bit en los que se define dos nuevos tipos de datos: signed y unsigned. Estos tipos son parecidos a los tipos std_logic_vector o bit_vector y son parte de una norma emergente (IEEE 1076.3) para desempeñar operaciones numéricas sobre señales vectorizadas. El paquete numeric_bit define a estos tipos (unsigned y signed) como un vector cuyos elementos son del tipo bit y el paquete numeric_std define los mismos pero con elementos del tipo std_logic. El propósito de estos dos tipos es el de representar números enteros positivos y negativos en forma binaria. Para ambos tipos, el bit más significativo está a la izquierda. El tipo signed se utiliza para representar un número entero con signo en forma binaria con complemento a dos, y el unsigned es solamente un número entero sin signo en forma binaria. El paquete numeric_std define funciones y operadores aritméticos, relacionales, lógicos y de asignación para ser utilizados con estos tipos de datos. Signed, unsigned y std_logic_vector son tipos diferentes por lo que no se pueden mezclar. Sin embargo, varias funciones de conversión, tales como to_unsigned, son definidas para la conversión entre los tipos. EJEMPLOS x1 <= "0001"; IEC FRANCISCO JAVIER TORRES VALLE 27 CAPÍTULO III: SINTAXIS DEL LENGUAJE 3.4.3 SUBTIPOS Un subtipo es un “subgrupo” de un tipo predefinido. Los subtipos son útiles para crear tipos de datos con limitaciones sobre tipos mayores. DECLARACIÓN DE SUBTIPOS SUBTYPE identif IS tipobase RANGE <rango>; EJEMPLOS SUBTYPE byte IS bit_vector (7 DOWNTO 0); SUBTYPE digito IS integer RANGE (0 TO 9); Estos ejemplos definen dos subtipos llamados byte y digito. Las señales o variables que son declaradas como byte son del tipo std_logic_vector de 8 bits en orden descendente. Las señales o variables que sean declaradas como tipo digito serán del tipo entero, consistiendo de los posibles valores de los enteros del 0 al 9, inclusive. En el siguiente ejemplo se muestra como se pueden crear subtipos de datos a partir de aquellos tipos que sean definidos por el usuario. EJEMPLOS TYPE arith IS (add, sub, mul, div); SUBTYPE add IS arith RANGE add TO sub; SUBTYPE mul IS arith RANGE mul TO div; paquete STANDAR, que es utilizado por la mayoría de las herramientas de síntesis, no es utilizado por completo. A continuación se muestra una parte del paquete STANDAR donde se encuentran los tipos y subtipos predefinidos más utilizados. PACKAGE standard IS TYPE boolean IS (FALSE, TRUE); TYPE bit IS ('0', '1'); TYPE character IS ( NUL, SOH, STX, ETX, EOT, ENQ, ACK, BEL, BS, HT, LF, VT, FF, CR, SO, SI, DLE, DC1, DC2, DC3, DC4, NAK, SYN, ETB, CAN, EM, SUB, ESC, FSP, GSP, RSP, USP, ' ', '!', '"', '#', '$', '%', '&', ''', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\', ']', '^', '_', ''', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', DEL); TYPE integer IS RANGE -2147483647 TO 2147483647; SUBTYPE natural IS integer RANGE 0 TO 2147483647; SUBTYPE positive IS integer RANGE 1 TO 2147483647; TYPE string IS ARRAY (positive RANGE <>) OF character; TYPE bit_vector IS ARRAY (natural RANGE <>) OF bit; END standard; Los únicos subtipos predefinidos son el natural y el positive. 3.4.5 3.4.4 TIPOS PREDEFINIDOS EN VHDL Algunos tipos no son muy utilizados aunque existen dentro del lenguaje, como el characer o el string, y hay otros que no son soportados por las herramientas de síntesis. Los tipos no soportados son ignorados y por lo tanto no pueden ser sintetizados. Cada herramienta de síntesis define cuales son los tipos, objetos o estructuras de lenguaje que son o no soportados por la misma, a continuación se muestran lo tipos y objetos no soportados por el FOUNDATION. Dentro del estándar VHDL de la IEEE se describen dos paquetes en los que se especifica el conjunto de tipos de datos y operaciones en las que dichos tipos de datos pueden ser utilizados, estos paquetes son: STANDARD y TEXTIO. El paquete STANDAR de tipos de datos esta incluido en todos archivos fuente de VHDL, es decir, que no es necesario declararlo dentro de código para poder utilizarlo. El paquete TEXTIO define tipos de datos y operaciones para estos tipos para la comunicación con el software de síntesis que se este utilizando. Este no es necesario para la síntesis de circuitos y algunos programas de síntesis no lo soportan. De hecho, el IEC FRANCISCO JAVIER TORRES VALLE TIPOS NO SOPORTADOS EN VHDL PARA SÍNTESIS - Tipos físicos - Tipos reales o flotantes. - Objetos de datos ACCESS. Un ACCESS equivale a un apuntador y no es soportado por que no tiene ningún sentido en hardware. 28 CAPÍTULO III: SINTAXIS DEL LENGUAJE - Objetos de datos FILE. Estos se utilizan para almacenar datos en RAM o ROM de la computadora. IEC FRANCISCO JAVIER TORRES VALLE 29 CAPÍTULO III: SINTAXIS DEL LENGUAJE 3.5 OPERADORES Un operador nos permite construir diferentes tipos de expresiones mediante los cuales podemos calcular datos utilizando los diferentes objetos de datos con el tipo de dato que maneja dicho objeto. En VHDL existen distintos operadores de asignación con lo que se transfieren valores de un objeto de datos a otro, y operadores de asociación que relacionan un objeto de datos con otro, lo cual no existe en ningún lenguaje de programación de alto nivel. El uso de los operadores que aquí son expuestos dependerá del software utilizado, ya que no es regla que los utilicen todos. Para conocer las operaciones que pueden ser utilizadas así como los paquetes incluidos en el software, es recomendable revisar las librerías del programa. De no encontrarse algún operador especial para ser utilizado con algún tipo de dato especifico, es necesario sobrecargar los operadores o en ocasiones crearlo. Como sobrecargar operadores y como crear funciones se expone dentro del tema de subprogramas. Para poder utilizar la mayoría de estos operadores con los tipos signed, unsigned y std_logic_vector, basta con utilizar el paquete donde se encuentran declarados estos tipos, porque dentro de los mismos paquetes ya se encuentran sobrecargada varias funciones aritméticas y lógicas para que sean utilizadas con estos tipos, en temas posteriores se incluyen las funciones que se encuentran en los paquetes std_logic_1164, numeric_std y numeric_bit. TIPOS DE OPERADORES Los operadores lógicos no tiene orden de precedencia por lo que para expresiones en las que se utilice más de un operador lógico es necesario indicar mediante paréntesis cual es el orden en que se debe realizar el cálculo. EJEMPLOS x <= y ----- AND z OR w esta forma de utilizar los op. lógicos, es incorrecta y producirá un error cuando sea compilado el código x <= y AND ( z OR w ) -- forma correcta de utilizar los -- op.lógicos 3.5.2 OPERADORES DE COMPARACIÓN Estos tipos de operadores se utilizan para ejecutar pruebas de igualdad, desigualdad, o de magnitud entre dos objetos de datos. Los operandos que participen en la prueba deben ser del mismo tipo y el resultado de la operación es del tipo boolean. Los operadores de igualdad y desigualdad (= y /=) pueden ser utilizados para todos los tipos de datos predefinidos en el lenguaje Los operadores de magnitud (“<” menor que, “>” mayor que, “<=” menor o igual que, y “>=” mayor o igual que) están definidos para ser utilizados con tipos escalares. EJEMPLO SIGNAL x, y: bit_vector ( 3 DOWNTO 0) SIGNAL z : bit; AND, OR, NAND, NOR, XOR, XNOR, NOT COMPARACIÓN =, /=, <, >, <=, >= ADICIÓN +, -, & MULTIPLICACIÓN *, /, MOD, REM MISCELÁNEOS ABS, ** ASIGNACIÓN <=, := ASOCIACIÓN => CORRIMIENTO SLL, SRL, SLA, SRA, ROL, ROR LÓGICOS 3.5.1 OPERADORES LÓGICOS Los operadores lógicos AND, OR, NAND, NOR XOR, XNOR, y NOT están definidos para ser usados con los tipos bit y boolean. Para utilizar estos operadores, excepto el operador NOT, los operandos deben ser del mismo tamaño. IEC FRANCISCO JAVIER TORRES VALLE z <= '1' WHEN x >= z ELSE '0'; 3.5.3 OPERADORES DE ADICIÓN Los operadores + y - son frecuentemente utilizados para describir sumas y restas además de signos positivo y negativo. Están definidos para ser utilizados con el tipo entero. El operador “&” permite concatenar cadenas de bits obteniendo una de mayor tamaño. Los tres operadores tienen la misma precedencia, por lo que para instrucciones en la que se utiliza más de un operador de este tipo es recomendable indicar mediante paréntesis el orden de las operaciones. 30 CAPÍTULO III: SINTAXIS DEL LENGUAJE Para poder realizar operaciones de suma o resta entre un entero y un objeto de datos que represente una cadena de bits, lo mejor es declarar este objeto de datos como signed o unsigned e incluir el paquete numeric_std o el numeric_bit, ya que en estos se sobrecargaron los operadores “+” y “-” para que pudieran ser utilizados de esta manera. De lo contrario resultaría en un error de compilación al realizar dichas operaciones. Por otra parte no es posible realizar sumas entre bit_vectors de diferente tamaño, y tampoco podremos asignar el resultado de una suma o resta entre dos bit_vectors a un bit_vector de diferente longitud. Si se desea obtener el acarreo de la suma del resultado de una operación aritmética entre dos bit_vectors de la misma longitud, a un bit_vector que sea de mayor longitud en un bit, se permite utilizar el operador de concatenación para incrementar el tamaño solamente en el primer bit_vector que participa en la operación, con lo cual se indica que deseamos obtener el acarreo de la suma. EJEMPLOS SIGNAL conteo: integer RANGE 0 TO 255; SIGNAL x, y, z: signed( 7 downto 0); SIGNAL r, m: signed( 8 downto 0); conteo <= conteo + 1; x <= y + z + 5; r <= '0'z + x; -- de esta manera se -- obtiene el acarreo de -- la suma m <= r +1; 3.5.4 OPERADORES DE MULTIPLICACIÓN Son los operandos “*” y el “/” que se utilizan para la multiplicación y para la división respectivamente. Los dos operandos tienen el mismo orden de precedencia al igual que los operandos MOD y REM. Todos los operandos de multiplicación están definidos para ser utilizados con operandos del mismo tipo, siendo estos del tipo entero o bit_vector. El resultado es entonces del mismo tipo que los operandos por lo que también el objeto de datos que recibe el resultado de la operación deberá ser del mismo tipo que los operandos. La operación REM se define como se muestra a continuación: IEC FRANCISCO JAVIER TORRES VALLE A REM B = A-(A/B)*B La división es entera, por lo que los operandos deben ser del tipo entero. El resultado toma el signo de A. MOD calcula el módulo de dos números. Se define como: A MOD B = A-B*N Donde N es un entero. El resultado toma el signo de B. 3.5.5 OPERADORES MISCELÁNEOS En esta categoría se encuentran los operadores “abs” y “**”. El operador “abs” devuelve el valor absoluto de un operando del tipo entero. El operador ** se utiliza para elevar el primer operador a una potencia definida por el segundo operando, ambos deben ser del tipo entero. EJEMPLO CONSTANT r: integer := 2; VARIABLE i: integer; FOR n IN 0 TO 5 LOOP i := i + r**n; END LOOP; 3.5.6 OPERADORES DE ASIGNACIÓN En VHDL existen dos tipos de operadores de asignación los cuales son: "<=" y ":=". El operador ":=" se utiliza para asignar un valor inicial a constantes, variables y señales en el momento de la declaración, pero para el resto de la descripción únicamente utilizaremos ":=" para ser usado con variables y "<=" para ser usado con señales. ASIGNACIÓN A VARIABLES nombre_variable := expresión; ASIGNACIÓN A SEÑALES nombre_señal <= expresión; Las asignaciones a variables solamente pueden ocurrir dentro de los procesos o subrutinas, las asignaciones a señales pueden ocurrir en cualquier lugar dentro de la descripción. 31 CAPÍTULO III: SINTAXIS DEL LENGUAJE Para realizar asignaciones a objetos de datos de tipos compuesto, se pueden realizar utilizando agregados. Los agregados son una lista de varios valores encerrados entre paréntesis y separados mediante comas de tal forma que el primer elemento de la lista es asignado al primer elemento del objeto, el segundo elemento de la lista es asignado al segundo elemento del objeto de datos etc. Así mediante una sola instrucción se asignan varios valores al objeto de datos. EJEMPLOS TYPE op IS (suma, resta, mult, div); TYPE reg_datos IS RECORD operador: op; x: integer; y: bit; END RECORD; . . . VARIABLE registro: reg_datos; SIGNAL vec1, vec2: bit_vector(0 TO 3); . . . vec1 <= ('0', '1', '1', '0'); -- asignación mediante agregados vec2 <= vec1; -- también esta es una asignación -- mediante agregados registro := ( resta, 13, '1' ); -- asignación a variable del tipo -- record mediante agregados vec2 <= ( '1', OTHERS => '0' ); -- en esta asignación se hace '1' -- el elemento 0 de vector2 y el resto -- se hacen cero 3.5.7 OPERADORES DE ASOCIACIÓN En diseños jerárquicos generalmente se hace uso de varios componentes, los cuales son entidades que realizan ciertas funciones especificas. Para poder especificar las conexiones de puertos entre dichos componentes y con los puertos de la entidad principal es necesario utilizar el operador de asociación "=>". El orden con el que se asocian dichas conexiones depende del orden en el que fueron declarados los puertos del componente, además, deben ser del mismo tipo y del mismo modo. Diseños jerárquicos y componentes se explicaran detalladamente en temas posteriores. A continuación se muestra un ejemplo de cómo utilizar este operador de asociación. IEC FRANCISCO JAVIER TORRES VALLE EJEMPLO LIBRARY mi_libreria; USE mi_libreria.sumadores.ALL; ENTITY sumador IS PORT ( ci: IN bit; x: IN bit_vector(3 DOWNTO 0); y: IN bit_vector(3 DOWNTO 0); z: OUT bit_vector(3 DOWNTO 0); co: OUT bit); END sumador; ARCHITECTURE a_sumador OF sumador IS SIGNAL carry1: bit; SIGNAL carry2: bit; SIGNAL carry3: bit; BEGIN u0: add PORT MAP ( ci => ci, x0 => x(0), y0 => y(0), z0 => z(0), co => carry1 ); u1: add PORT MAP ( ci => carry1, x0 => x(1), y0 => y(1), z0 => z(1), co => carry2 ); u2: add PORT MAP ( carry2, x(2), y(2), z(2), carry3 ); u3: add PORT MAP ( carry3, x(3), y(3), z(3), co ); END a_sumador; El componente “add” esta declarado dentro del paquete “sumadores” de la librería “mi_libreria”, y esta declarado de la siguiente manera. ------------------------------------------- SUMADORES ------------------------------------------- paquete compilado en la librería -- "mi_librería" PACKAGE sumadores IS · · · COMPONENT add PORT ( ci: IN bit; x0: IN bit; y0: IN bit; z0: OUT bit; co: OUT bit ); END COMPONENT; · · · END PACKAGE; Observe como los puertos de la entidad “sumador”y las conexiones entre los bloques u0, u1, u2 y u3, se hicieron de acuerdo al orden en que los puertos están declarados en el componente. En el bloque u0 primero se hace la conexión del puerto "ci" del componente con el puerto “ci”de la entidad mediante le operador de 32 CAPÍTULO III: SINTAXIS DEL LENGUAJE asociación "=>", después se hace la conexión del puerto x0 del componente con el elemento 0 (LSB) del vector x de la entidad, y así sucesivamente hasta realizar todas las conexiones del componente “add”utilizado en el bloque u0. Lo mismo se hace con el bloque u1. En los bloques u2 y u3, las conexiones se realizaron con una notación equivalente pero simplificada. Los nombres no tienen que ser necesariamente los mismos e inclusive pueden ser diferentes, ya que cada puerto es un objeto de datos local para la entidad en la que fue declarado. Es importante mencionar que dentro del paquete “sumadores” se encuentra la entidad y la arquitectura correspondiente al componente “add”, en los que se describe el mismo. 3.5.8 OPERADORES DE CORRIMIENTO Incluidos en los paquetes numeric_std y numeric_bit, estos operadores realizan operaciones de desplazamiento o de rotación con los elementos de un vector del tipo signed o unsigned. DESPLAZAMIENTOS LÓGICOS SLL Y SRL Desplazan los bits de un vector n veces a la izquierda (SLL) o a la derecha (SRL), introduciendo ceros en los lugares que quedan libres. EJEMPLO x SRL 3 -- desplaza 3 lugares a la -- derecha los bits del vector "x" DESPLAZAMIENTOS ARITMÉTICOS SLA Y SRA También desplazan los bits de un vector n veces a la izquierda (SLA) o a la derecha (SRA), introduciendo ceros en los lugares que quedan libres, pero conservan el signo. ROTACIONES ROL Y ROR Se desplazan los bits de un vector n veces a la izquierda (ROL) o a la derecha (ROR), introduciendo los bits que son desplazados en los lugares que van quedando libres. ROL ROR Figura 3.4 Instrucciones ROR y ROL 3.5.9 OPERACIONES CON VECTORES Todas las herramientas de síntesis proporcionan algún tipo de paquete en el que se encuentre definidas funciones que facilitan la descripción del diseño. Dentro de estos paquetes se encuentran funciones que están hechas específicamente para ser utilizadas con vectores y como por lo general es preferible utilizar vectores estos paquetes son de gran ayuda. Synopsys desarrolló paquetes basados en el paquete std_logic_1164, que son utilizados por varias herramientas de síntesis existentes en el mercado, como por ejemplo FOUNDATION de Xilinx, Inc. y MAX+PLUS II de Altera Corporation. Estos paquetes son: - std_logic_arith - std_logic_signed - std_logic_unsigned La compañía Actel también desarrolló su propio paquete de síntesis: - asyl.arith Y los paquetes que fueron desarrollados por la IEEE específicamente para síntesis de circuitos digitales. - numeric_bit - numeric_std Además del paquete que es el más utilizado por la mayoría de los paquetes de síntesis. - std_logic_1164 Todos estos paquetes son los más conocidos y utilizados para síntesis de circuitos, por lo que para poder utilizarlos primero debemos de incluir la librería en que fueron compilados para posteriormente hacer referencia al paquete que deseamos utilizar (una librería puede tener más de un paquete) como se muestra a continuación. EJEMPLO LYBRARY ieee; -- llamado a la librería USE ieee.std_logic_1164.ALL; -- referencia IEC FRANCISCO JAVIER TORRES VALLE 33 CAPÍTULO III: SINTAXIS DEL LENGUAJE ---------- o carga del paquete std_logic_1164 "ALL" es para indicar que deseamos utilizar todos los tipos de datos y funciones incluidas en el paquete USE ieee.numeric_std.ALL; -- referencia -- al paquete -- numeric_std 3.6 ATRIBUTOS Un atributo es una propiedad que es asociada a señales, entidades o arquitecturas. Estos atributos proporcionan información que nos puede ser útil dentro de una descripción en VHDL. Los atributos se utilizan mediante la comilla simple, por ejemplo el atributo 'event, que probablemente sea el más utilizado, nos permite detectar cuando sucede una transición de estado en una señal, por lo que es muy útil en descripciones de circuitos secuenciales. ATRIBUTOS PARA ARREGLOS 'left Obtiene el valor que se encuentra a la izquierda de un arreglo. ´right Regresa el dato que se encuentra a la derecha del arreglo. ´high Permite obtener el mayor elemento de un objeto de arreglo. ´low Proporciona el valor más pequeño del arreglo. 'lenght Con este atributo se obtiene el número de elementos de un arreglo. Un arreglo es un objeto de datos que esta compuesto por varios elementos de un tipo sencillo, como lo son los bit_vector y std_logic_vector. ATRIBUTOS DE SEÑALES 'event REFERENCIA A ATRIBUTOS nombre_objeto'nombre_atributo EJEMPLO IF ( clk'event and clk = '1' ) THEN A <= '1' ; END IF; En el ejemplo anterior se utiliza el atributo 'event, indicado en color verde, para detectar una transición en la señal clk, y al mismo tiempo comprobamos si esta transición fue positiva. Si ambas condiciones se cumplen entonces se asigna un '1' lógico a "A". El atributo 'event se utiliza solo para señales de clk ya que de otra manera no es posible sintetizar una transición en un dispositivo lógico programable, por lo que también debemos indicar que tipo de transición estamos utilizando. Existen más atributos y a continuación se mencionan algunos que son útiles en descripciones para síntesis. IEC FRANCISCO JAVIER TORRES VALLE El atributo event es del tipo boolean y retorna un valor verdadero cuando ocurre una transición en la señal a la que hace referencia. EJEMPLOS TYPE secuencia IS integer RANGE 0 TO 10; SIGNAL conteo: secuencia; · · · conteo'left = 0 conteo'rigth = 10 conteo'lenght = 11 conteo'high = 10 conteo'low = 0 3.7 ENTIDADES Una entidad es la abstracción de un circuito, ya sea desde un complejo sistema electrónico hasta una simple compuerta lógica. La entidad únicamente describe la forma externa del circuito, aquí se enumeran las entradas y salidas del diseño. Una entidad es análoga a un símbolo esquemático de los diagramas electrónicos, el cual describe las conexiones del dispositivo hacia el resto del diseño. 34 CAPÍTULO III: SINTAXIS DEL LENGUAJE DECLARACION DE ENTIDADES ENTITY identificador IS GENERIC ( cte_1: tipo := valor; cte_2: tipo := valor; · · · cte_n: tipo := valor ); PORT ( puerto_1: modo tipo; puerto_2: modo tipo; · · · puerto_n: modo tipo ) ; END identificador ; Note que la ultima línea de declaración de puerto o de genéricos no lleva punto y coma al final de la línea. EJEMPLO En este ejemplo se realiza la entidad de un multiplexor 4 a 1 que se muestra en la figura 3.5. ENTITY mux_4_1 IS PORT (a, b, c, d: IN bit; mux_signal: IN bit_vector(1 DOWNTO 0); x: OUT bit ); END mux_4_1; y: IN bit_vector(msb DOWNTO 0); equals: OUT bit; x_may_y: OUT bit; x_men_y; OUT bit); END comparador; 3.7.2 PUERTOS Cada entrada y salida de la entidad se declara dentro de la región puertos (PORT), en el momento de la declaración se debe indicar el modo y tipo del puerto. Los puertos los podemos asociar con los pines de un símbolo esquemático y, al igual que estos, algunos son únicamente entradas, otros salidas, o incluso bidirecionales. Un puerto es implícitamente un objeto de datos del tipo señal porque representa conexiones en el diseño, y puede ser utilizado en expresiones de programación dentro de la arquitectura que describe a dicha entidad. Cada puerto debe tener un nombre, un modo y se debe especificar el tipo de dato mediante el cual manipularemos dicho puerto en la descripción. 3.7.3 MODOS El modo indica la forma en que los datos fluyen a través del circuito. Estos pueden ser de uno de cuatro tipos: - IN - OUT - INOUT Figura 3.5 Multiplexor de 4 bits a 1 3.7.1 GENÉRICOS Esta instrucción es opcional y se utiliza para declarar propiedades y constantes del circuito. Estas constantes se utilizan al igual que las que se declaran por el usuario, por lo que nos permiten modelar circuitos en los que se pueden cambiar propiedades, tamaños de los buses de entrada o salida del circuito. Se utilizan generalmente en paquetes. EJEMPLO ENTITY comparador IS GENERIC(msb: integer := 3); PORT( x: IN bit_vector(msb DOWNTO 0); IEC FRANCISCO JAVIER TORRES VALLE - BUFFER Si no se indica ningún modo en la declaración, se asume que es del tipo IN. Un puerto del modo IN describe un pin del circuito que únicamente puede ser utilizado como entrada por lo que solamente podremos leer datos de dicho puerto y nunca escribir sobre él. Por el contrario, un puerto que sea declarado del modo OUT podrá ser utilizado para escribir datos pero no para ser leído, este representa un pin que únicamente es salida del circuito y que en él no existe ningún tipo de retroalimentación hacia dentro del diseño. Un puerto INOUT indica aquellos puertos que son pueden ser utilizados bidireccionalmente mientras que un puerto del modo BUFFER es utilizado para salidas que tienen retroalimentación interna. La diferencia entre el modo BUFFER y el INOUT, es que el INOUT es retroalimentado desde el pin de salida del circuito, en tanto que 35 CAPÍTULO III: SINTAXIS DEL LENGUAJE como un puerto del modo BUFFER lo hace internamente no puede ser usado como bidireccional. Figura 36 Modos de direccionamiento para puertos IEC FRANCISCO JAVIER TORRES VALLE 36 CAPÍTULO III: SINTAXIS DEL LENGUAJE 3.8 ARQUITECTURAS Los pares de entidades y arquitecturas se utilizan para representar la descripción completa de un diseño. Una arquitectura, describe el funcionamiento de la entidad a la que hace referencia. Si una entidad la asociamos con una "caja" en la que se enumeran las interfaces de conexión hacia el exterior, entonces la arquitectura representa la estructura interna de esa caja. Por ejemplo, el símbolo esquemático de un 74LS04 representaría la entidad del diseño, y la forma en que las compuertas son conectadas internamente corresponden a la arquitectura del circuito, y así ambos describen completamente el circuito. Figura 3.7 Entidad, Símbolo Esquemático EJEMPLO ENTITY mux_4_1 IS PORT ( a, b, c, d: IN bit; mux_signal: IN bit_vector(1 DOWNTO 0); x: OUT bit ); END mux_4_1; ARCHITECTURE a_mux_4_1 OF mux_4_1 IS BEGIN x <= a WHEN mux_signal = "00" ELSE b WHEN mux_signal = "01" ELSE c WHEN mux_signal = "10" ELSE d WHEN mux_signal = "11"; END a_mux_4_1; Una arquitectura describe el comportamiento, estructura o flujo de datos de la entidad a la que hace referencia. Una entidad puede tener más de una arquitectura, pero cuando se compile se indica cual es la arquitectura que queremos utilizar. Para describir el funcionamiento de la entidad se puede hacer uso de cualquiera de los tres estilos siguientes: - Descripción de Flujo de Datos - Descripción Comportamental - Descripción Estructural Figura 3.8 Arquitectura, Estructura Interna DECLARACIÓN DE ARQUITECTURA ARCHITECTURE identificador OF entidad IS -- declaraciones de la arquitectura BEGIN -- Código de Descripción -- instrucciones concurrentes -- ecuaciones booleanas -- PROCESS -instrucciones secuenciales END identificador_arquitectura; Antes del BEGIN se escriben todas las declaraciones que se necesiten dentro de la descripción, tales como: señales, constantes, funciones, alias, componentes, tipos de datos etc. Después del BEGIN es donde se realiza todo el código de descripción del circuito. IEC FRANCISCO JAVIER TORRES VALLE Los tres estilos son diferentes, pero esto no significa que se tenga que utilizar únicamente un estilo. De hecho lo mejor es tratar de utilizar los tres como mejor nos convenga. En el siguiente tema se explica el estilo de descripción de flujo de datos, así como el tipo de instrucciones que participan en este estilo. 3.9 DESCRIPCIONES DE FLUJO DE DATOS Una descripción de flujo de datos consiste en especificar como los datos son transferidos de las entradas a las salidas. Cabe mencionar que algunos autores distinguen las descripciones de flujo de datos de las comportamentales, en tanto que para otros ambos estilos son del tipo comportamental. La principal diferencia entre estas es el tipo de instrucciones que utilizan, además que en un estilo comportamental se utiliza el bloque PROCESS en tanto que en el estilo en cuestión no se utiliza. 37 CAPÍTULO III: SINTAXIS DEL LENGUAJE En este estilo de descripción se utilizan únicamente asignaciones mediante expresiones en las que se indica como cambian los puertos de salida en función de los puertos de entrada, ya sean asignaciones condicionales mediante instrucciones concurrentes o simples ecuaciones. Un ejemplo de descripción de flujo de datos es el comprador utilizado en el primer tema de este capítulo, en éste los datos son los que indican la forma en que cambian las salidas y por esto se le llama de flujo de datos. 3.9.1 INSTRUCCIONES CONCURRENTES En lenguajes de programación como C o Pascal, cada instrucción de asignación es ejecutada una después de otra en un orden especifico. El orden en el que las instrucciones son ejecutadas es determinado por el orden de las instrucciones en el archivo. Dentro de una arquitectura en VHDL, no existe un orden especifico de ejecución de las asignaciones. El orden en el que las instrucciones son ejecutadas depende de los eventos ocurridos en las señales, similar al funcionamiento de un circuito. En VHDL todos los bloques son concurrentes, es decir que se están ejecutando en todo momento. Después se explicará el bloque PROCESS, el cual está compuesto por una serie de instrucciones que sí se ejecutan en el orden en el que fueron especificadas. Las instrucciones concurrentes se utilizan fuera de un bloque PROCESS, a diferencia de las instrucciones secuenciales que únicamente se utilizan dentro del bloque concurrente PROCESS y en subprogramas. EJEMPLO gray <= "00" WHEN binario = x"0" ELSE "01" WHEN binario = x"1" ELSE "11" WHEN binario = x"2" ELSE "10"; • ASIGNACIÓN WHIT... SELECT... WHEN SINTAXIS WITH identificador SELECT signal_name1 <= expresión valor_a WHEN valor_b WHEN · · · valor_n WHEN WHEN valor1, valor2, valor3, OTHERS ; EJEMPLO WITH states SELECT salida <= "000" WHEN state0, "001" WHEN state1, "010" WHEN state2, "100" WHEN state3, "000" WHEN OTHERS; No olvidar la coma al final de cada línea, excepto en la ultima que lleva punto y coma. • ECUACIONES BOOLEANAS signal_name <= ecuación_booleana; EJEMPLOS x <= y AND z; a <= ( b OR c OR d ) AND e ; -- cuando se utilice más de un operador -- lógico es necesario utilizar paréntesis op1 <= op2 NOR op3 NOR op4; 3.9.2 • ESTRUCTURAS DE EJECUCIÓN CONCURRENTE ASIGNACIÓN CONDICIONAL WHEN... ELSE SINTAXIS signal_name <= valor_a WHEN condición ELSE valor_b WHEN condición ELSE valor_c WHEN condición ELSE valor_d WHEN condición ELSE · · · valor_n WHEN condición ELSE otro_valor; 3.9.3 A continuación se muestra la tabla de funcionamiento de una pequeña unidad aritmético — lógica la cual consta de dos bits de entrada, un bit de salida, acarreo de entrada y acarreo de salida. TABLA DE FUNCIONAMIENTO ENTRADAS s1 IEC FRANCISCO JAVIER TORRES VALLE ALU s0 SALIDAS z co 38 CAPÍTULO III: SINTAXIS DEL LENGUAJE 0 0 x AND y 0 0 1 x OR y 0 1 0 x XOR y 0 1 1 x + y + ci acarreo de la suma CÓDIGO DE DESCRIPCIÓN LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE ieee.numeric_std.ALL; ENTITY alu IS PORT ( x, y: IN std_logic; s0, s1: IN std_logic; ci: IN std_logic; z: OUT std_logic; co: OUT std_logic); END alu; instrucciones no importa dentro de una descripción, recordemos que VHDL describe circuitos y por lo tanto todas las asignaciones (conexiones) siempre están funcionando al igual que todos los dispositivos dentro de un circuito. Las señales suma, acarreo, and_op, or_op y xor_op son las salidas de varios bloques del circuito, cada uno con una función distinta. El bus "seleccion" se compone de los dos bits de entrada s0 y s1, estas se juntan en este bus únicamente para facilitarnos la descripción. Y mediante los bloques de la instrucción WITH... SELECT... WHEN y la instrucción WHEN... ELSE se asignan los datos correspondientes a cada salida de a cuerdo a las combinaciones de los bits s0 y s1. ARCHITECTURE a_alu OF alu IS SIGNAL seleccion: unsigned(1 DOWNTO 0); SIGNAL suma: std_logic; SIGNAL and_op: std_logic; SIGNAL or_op: std_logic; SIGNAL xor_op: std_logic; SIGNAL acarreo: std_logic; BEGIN and_op <= x AND y ; WITH seleccion SELECT z <= or_op WHEN "01", and_op WHEN "00", suma WHEN "11", xor_op WHEN "10", '0' WHEN OTHERS; seleccion <= s1 & s0; suma <= x XOR y XOR ci; or_op <= x OR y; acarreo <= (x AND y) OR (x AND ci) OR (y AND ci); xor_op <= x XOR y; co <= acarreo WHEN seleccion = 3 ELSE '0' ; END a_alu; Este circuito se sintetizo en un GAL22V10 utilizando WARP 5.0 de Cypress Semiconductors. Obsérvese que en el código de descripción de esta alu no existe ningún orden en las ecuaciones, asignaciones o instrucciones, de hecho el orden en el que se coloquen las IEC FRANCISCO JAVIER TORRES VALLE Figura 3.9 Diagrama a bloques de la ALU El que hayamos realizado la descripción con tantos bloques no significa necesariamente que cuando el compilador sintetice el código respete todos esos bloques y quede exactamente como lo describimos dentro del dispositivo que seleccionamos. El compilador de WARP interpreta nuestra descripción y la sintetiza dentro del dispositivo utilizando el mínimo de compuertas posible al mismo tiempo que trata de respetar la descripción del código, además, que por lo general trata de evitar retroalimentaciones 39 CAPÍTULO III: SINTAXIS DEL LENGUAJE para que el dispositivo funcione a altas velocidades. De hecho en ocasiones es posible que existan todavía macroceldas libres, pero como el compilador evita retroalimentaciones, entonces no las usa. Como indicar que se usen esas macroceldas libres se explicará posteriormente, ya que este circuito sí puede quedar dentro de un GAL16V8 utilizando directivas de síntesis. A continuación se muestran las ecuaciones, la asignación de pines y el informe de utilización del dispositivo obtenidos por el compilador de WARP. ------------------------------------------ ECUACIONES Summary: Error Count = 0 Warning Count = 0 Completed Successfully ------------------------------------------ -----------------------------------------PLD Compiler Software: MAX2JED.EXE 02/APR/1999 [v4.02 ] 5.2 IR 17 -----------------------------------------UTILIZACIÓN DESIGN EQUATIONS (05:56:54) -----------------------------------------PLD Compiler Software: PLA2JED.EXE 02/APR/1999 [v4.02 ] 5.2 IR 17 RESOURCE UTILIZATION (06:15:25) Information: Macrocell Utilization. Information: Output Logic Product Term Utilization. Completed Successfully ------------------------------------------ -----------------------------------------PIN – OUT -----------------------------------------PLD Compiler Software: PLA2JED.EXE 02/APR/1999 [v4.02 ] 5.2 IR 17 PINOUT INFORMATION (06:15:24) Completed Successfully ------------------------------------------ Messages: Information: Checking for duplicate NODE logic. None. IEC FRANCISCO JAVIER TORRES VALLE 40 CAPÍTULO III: SINTAXIS DEL LENGUAJE 3.10 DESCRIPCIONES COMPORTAMENTALES Las descripciones comportamentales son similares a un lenguaje de programación de alto nivel, por su alto nivel de abstracción. Mas que especificar la estructura o la forma en que se deben conectar los componentes de un diseño, nos limitamos a describir su comportamiento. Una descripción comportamental consiste de una serie de instrucciones, que ejecutadas secuencialmente, modelan el comportamiento del circuito. La ventaja de una descripción comportamental es que no necesitamos enfocarnos a un nivel de compuerta para implementar un diseño. En VHDL una descripción comportamental necesariamente implica el uso de por lo menos un bloque PROCESS. 3.10.1 INSTRUCCIONES SECUENCIALES Las instrucciones secuenciales son aquellas que son ejecutadas serialmente, una después de otra. La mayoría de los lenguajes de programación, como C o Pascal, utilizan este tipo de instrucciones. En VHDL las instrucciones secuenciales son implementadas únicamente dentro del bloque PROCESS 3.10.2 PROCESOS Un proceso es el bloque básico concurrente de codificación secuencial. Contiene una serie de instrucciones secuenciales que permiten modelar el comportamiento del circuito, sin embargo, el bloque PROCESS equivale a una sola instrucción concurrente. Un proceso puede ser utilizado dentro de cualquier arquitectura definiendo para si mismo una región de declaraciones y otra para la codificación secuencial, similar a una arquitectura. La región de codificación puede contener únicamente instrucciones secuenciales (IF, CASE, FOR, etc.) en tanto que la región de declaraciones permite designar constantes, señales, tipos de datos o algún alias. SINTAXIS PROCESS ( lista sensible ) -- declaraciones BEGIN -- instrucciones secuenciales END PROCESS; IEC FRANCISCO JAVIER TORRES VALLE La lista sensible define cuales señales provocan que las instrucciones dentro del bloque comiencen a ser ejecutadas. Los cambios en alguna de las señales provocan que el proceso sea llamado. Un proceso que no tenga lista sensible debe utilizar una instrucción WAIT para especificar cuando deben ser ejecutadas las instrucciones dentro del bloque. La mayoría de las herramientas de síntesis tienen problemas si las lista sensible no está completamente especificada. Estas consideran que mediante el proceso estamos modelando lógica combinacional o secuencial. La lista sensible es parcialmente declarada cuando alguna de las señales que intervienen en lado derecho de una ecuación o de alguna instrucción secuencial no es mencionada dentro de la lista. El que la lista no este completa generalmente produce que no sea posible modelar totalmente la funcionalidad del diseño y por lo tanto no es posible obtener las ecuaciones durante el proceso de síntesis. El funcionamiento del proceso es similar a un microprocesador que funciona únicamente con interrupciones. La señales dentro de la lista sensible hacen a su vez de entradas de interrupción y las instrucciones secuenciales se encuentran dentro de una rutina única de servicio de interrupción. Cuando alguna de las señales de la lista sensible cambia, provoca que el proceso comience a funcionar y a ejecutar toda esta rutina de ejecución secuencial con la particularidad de que los que resulte de este procesamiento se asigne únicamente al final de la estructura. Por lo que podemos manipular los valores de las señales y esto no implica que cambien con cada asignación sino solamente hasta que se termina de ejecutar todo el proceso. Y como las asignaciones a los nodos del circuito se hacen al final, entonces todo la estructura del proceso es similar a un dispositivo de ejecución secuencial, como un microprocesador, que forma parte del diseño. Esta comparación con un microprocesador no implica que siempre debamos especificar una señal de reloj para el funcionamiento de la estructura, o que únicamente nos permita modelar circuitos secuenciales. De hecho, si suponemos que la frecuencia de trabajo de este "microprocesador" es muy grande, entonces las instrucciones dentro de la estructura se ejecutan tan rápido que prácticamente lo podríamos considerar combinacional. Si alguna señal de reloj es especificada, entonces estamos limitando a que 41 CAPÍTULO III: SINTAXIS DEL LENGUAJE las instrucciones dentro del proceso sean ejecutadas únicamente dentro de alguna transición de esta señal, lo cual no permite describir circuitos secuenciales. EJEMPLO A continuación se muestra el código de descripción comportamental del comparador de la figura 3.10. ENTITY comparador IS PORT( x: IN bit_vector(3 DOWNTO 0); y: IN bit_vector(3 DOWNTO 0); equals: OUT bit; x_may_y: OUT bit; x_men_y: OUT bit); END comparador; ARCHITECTURE comparador OF comparador IS BEGIN PROCESS(x, y) BEGIN equals <= '0'; x_may_y <= '0'; x_men_y <= '0'; IF x = y THEN equals <= '1'; END IF; IF x > y THEN x_may_y <= '1', END IF; IF x < y THEN x_men_y <= '1'; END IF; END PROCESS; END comparador; Figura 3.10 Comparador Este ejemplo corresponde al mismo comprador utilizado en el tema 3.1.2. Se definen 2 vectores de 4 bits y 3 salidas de 1 bit. Esta arquitectura únicamente tiene una instrucción concurrente: el bloque PROCESS, el cual es sensible a los vectores de entrada. Siempre que ocurra un cambio en alguno de estos, el proceso será llamado y generará la lógica de salida. La lista sensible está completa porque, si observamos, el IEC FRANCISCO JAVIER TORRES VALLE estado de las salidas depende únicamente de las entradas. Cada instrucción será ejecutada en orden secuencial y cuando todas hallan sido ejecutadas, entonces se asigna el valor procesado a los nodos que se vieron afectados durante el proceso. Una vez que se terminó de ejecutar el proceso, éste se mantendrá inactivo hasta que alguno dos elementos de la lista sensible cambie. Cuando se utilicen procesos se debe tener cuidado de no olvidar alguna combinación posible de entradas y/o salidas retroalimentadas que tal vez no estemos considerando o que no necesitamos. En estos casos es recomendable utilizar el tipo std_logic o, si son vectores, algún tipo que se base en este. Los valores '-' y 'Z' del std_logic son permitidos en síntesis siempre y cuando se utilicen correctamente. EJEMPLO ARCHITECTURE simplifica OF entidad_x IS SIGNAL y_tmp:std_logic_vector(1 DOWNTO 0); BEGIN PROCESS(s) BEGIN IF (s = 0) OR (s = 3) THEN -- s es un vector del tipo unsigned y_tmp <= '1'; ELSIF s = 1 THEN y_tmp <= '0'; ELSE y_tmp <= '-'; END IF; END PROCESS; y <= y_tmp WHEN enable = '0' ELSE 'Z'; -- "y" y "y_tmp" son tipo std_logic END simplifica; En el ejemplo anterior únicamente nos importan las combinaciones s = 3, s = 1, y s = 0. En algunos programas de VHDL para síntesis, y también dependiendo de la arquitectura del dispositivo, la asignación de un "no importa" nos va a permitir que se simplifique la ecuación de y_tmp, quedando como: y_tmp = s(1) +s(0)' De no utilizarla posiblemente quede de la siguiente forma: y_tmp = s(0)'·s(1)' + s(0)·s(1) 42 CAPÍTULO III: SINTAXIS DEL LENGUAJE 3.10.3 DIFERENCIAS ENTRE SEÑALES Y VARIABLES Un objeto de datos del tipo señal es muy diferente a uno del tipo variable. Ya se había mencionado que las señales pueden ser sintetizados en elementos lógicos y/o conexiones, lo cual no es posible con un variable. Una señal representa un nodo de conexión entre elementos lógicos (compuertas, registros, buffers, etc.). Inclusive un mismo nodo puede recibir más de un nombre para facilitar la descripción, sin que esto implique más términos en las ecuaciones de salida. Una señal que se vea involucrada dentro de un proceso no recibe inmediatamente el valor asignado, sólo hasta el final del mismo. Una variable que sea utilizada dentro de un proceso sí recibe el valor de forma inmediata, por lo que son muy útiles para poder obtener el estado de salida deseado para alguna señal de salida. Una variable funciona exactamente igual que cualquier variable de cualquier lenguaje de programación de software. Podemos decir que una señal está formada por dos partes: un valor actual y un valor futuro (o valor en proceso). El valor futuro es el que se calcula dentro del proceso y una vez que se termina el proceso, los valores futuros de todas las señales se convierten en valores actuales. Al valor futuro se le conoce como driver. En VHDL para síntesis el driver nunca es afectado fuera de un proceso, fuera de éste siempre estamos modificando el valor actual. EJEMPLO ENTITY proceso IS PORT( x, y: IN bit; z1, z2, z3: OUT bit ); END proceso; ARCHITECTURE ejemplo_proceso OF proceso IS BEGIN PROCESS (x,y) VARIABLE z_var: bit; SIGNAL z_sig: bit; BEGIN z_var := '1'; -- z_var = '1' z_sig <= '1'; -- driver de z_sig = '1' z1 <= z_var; -- driver de z1 = z_var = x, -- esto es valido porque son -- objetos que manejan el mismo -- tipo de datos z2 <= z_sig; -- z2 = z_sig = x AND y END PROCESS; -- finalizado el proceso, -- valor actual de z1 = x -- valor actual de z2 = x AND y z3 <= x OR y; -- valor actual de z3 = x OR y, -- en todo momento END ejemplo_proceso; Otro detalle importante en VHDL para síntesis, es que el valor actual de una señal no puede verse modificado más de una vez dentro de la arquitectura, porque las señales representan conexiones y esto equivaldría a unir dos cables. Y esto generalmente resultará en un error de compilación durante el proceso de síntesis. EJEMPLOS ARCHITECTURE no_valida1 OF senial IS BEGIN z <= x AND y; z <= x OR y; END no_valida1; ARCHITECTURE no_valida2 OF senial IS BEGIN PROCESS(x, y) BEGIN z <= x OR y; -- driver de z = x OR y END PROCESS; -- finalizado el proceso, -- valor actual de z = x OR y z <= x AND y; -- ERROR, se vuelve a -- modificar el valor actual de z END no_valida2; ARCHITECTURE valida1 OF senial IS BEGIN PROCESS(x, y) BEGIN z <= x AND y; -- driver de z = x AND y z <= x OR y; -- se modifica el driver -- de z, driver de z = x OR y END PROCESS; -- finalizado el proceso, -- valor actual de z = x OR y END valida1; z_var := x AND z_var; -- z_var = x AND '1' -- z_var = x z_sig <= x AND y; -- driver de z_sig = x AND y IEC FRANCISCO JAVIER TORRES VALLE 43 CAPÍTULO III: SINTAXIS DEL LENGUAJE 3.10.4 ESTRUCTURAS DE EJECUCIÓN SECUENCIAL • IF - THEN - ELSE SINTAXIS IF condición THEN · · · ELSIF condición THEN · · · END IF; EJEMPLO SIGNAL conteo: unsigned(3 DOWNTO 0); · · · IF conteo = X"9" THEN conteo <= ( OTHERS => '0' ) ; ELSE conteo <= conteo + 1; END IF; • CASE - WHEN CASE expresión IS WHEN alternativa1 => · · · WHEN alternativa2 => · · · WHEN OTHERS => · · · END CASE; EJEMPLO TYPE estados IS (estado1, estado2, estado3, estado4); SIGNAL estado_maquina: estados; SIGNAL motor, alarma: bit; CONSTANT encendido: bit := '1'; CONSTANT apagado: bit := '0'; · · · CASE estado_maquina IS WHEN estado0 => motor <= apagado; WHEN estado1=> motor <= encendido; WHEN (estado3 OR estado4) => alarma <= encendido; WHEN OTHERS => motor <= apagado; alarma <= apagado; END CASE; • FOR - LOOP FOR identificador IN rango LOOP · · · END LOOP; IEC FRANCISCO JAVIER TORRES VALLE EJEMPLO FOR i IN 3 DOWNTO 0 LOOP -- i es una variable y no necesita ser -- declarada IF reset ( i ) = '1' THEN data_out ( i ) <= '0'; END IF; END LOOP; • WHILE - LOOP WHILE condición LOOP · · · END LOOP; EJEMPLO contador := 0; resultado_tmp := 0; WHILE contador > 0 LOOP contador := contador - 1; resultado_tmp:= resultado_tmp+data_in; END LOOP; resultado <= resultado_tmp; • WAIT La instrucción WAIT es utilizada en procesos que no tienen una lista sensible, ya que esta instrucción define implícitamente la lista sensible del proceso. A continuación se muestran las 3 formas de utilizar la instrucción WAIT. WAIT ON -- espera los cambios de las -- señales especificada WAIT UNTIL -- espera a que se cumpla la -- condición especificada WAIT FOR -- detiene la simulación -- durante el tiempo -- especificado La instrucción WAIT ON no es aceptada por la mayoría de los herramientas de síntesis, WAIT FOR solo se utiliza para simulaciones. La única forma en que puede ser utilizada la instrucción WAIT en síntesis sin tener problemas es utilizándola como WAIT UNTIL. EJEMPLO PROCESS BEGIN WAIT UNTIL rising_edge( clk ) ; -- la función rising_edge viene -- incluida en el paquete -- std_logic_1164 y -- equivale a utilizar: -- clk'event AND clk = '1' IF reset = '1' THEN 44 CAPÍTULO III: SINTAXIS DEL LENGUAJE y <= (OTHERS => '0'); ELSE y <= y + 1; END IF; END PROCESS; IEC FRANCISCO JAVIER TORRES VALLE 45 CAPÍTULO III: SINTAXIS DEL LENGUAJE 3.11 DESCRIPCIONES ESTRUCTURALES En el siguiente ejemplo se muestra el código para una descripción estructural correspondiente al circuito de la figura 3.11. Las descripciones estructurales son útiles cuando se trata de diseños jerárquicos. Este ejemplo pretende mostrar como son este tipo de descripciones, aunque no es una aplicación práctica utilizar este estilo con circuitos sencillos como el anterior. 3.11.1 COMPONENTES Un componente representa a una entidad declarada en un diseño o librería, la utilización de componentes es útil en diseños jerárquicos como se mostró en el ejemplo anterior. Para poder utilizar una entidad que está dentro de otro diseño, es necesario llamar la librería y el paquete dentro del cual se encuentra esta entidad. Figura 3.11 Descripciones Estructurales LIBRARY mi_librería; USE mi_libreria.compuertas.ALL; ENTITY structural IS PORT ( x, y: IN bit; z: OUT bit); END structural; ARCHITECTURE estructural OF structural IS SIGNAL nodo1: bit; SIGNAL nodo2: bit; SIGNAL nodo3: bit; SIGNAL nodo4: bit; SIGNAL nodo5: bit; BEGIN U1: not_gate PORT MAP(x, nodo1); -- (entrada, salida) U2: not_gate PORT MAP(y, nodo2) ; -- (entrada, salida) U3: and_gate PORT MAP(nodo1, y, nodo3); -- (entrada, entrada, salida) U4: and_gate PORT MAP(nodo3, nodo2, nodo4 ); U5: and_gate PORT MAP(nodo2, x, nodo5); U6: or_gate PORT MAP(nodo4, nodo5, z); -- (entrada, entrada, salida) END estructural; Esta descripción utiliza entidades descritas y compiladas previamente dentro del paquete "compuertas" de la librería "mi_librería". Una descripción estructural es similar a un netlist de PSPICE. Se declaran los componentes que se utilizan y después, mediante los nombres de los nodos, se realizan las conexiones entre compuertas. IEC FRANCISCO JAVIER TORRES VALLE DECLARACIÓN DE COMPONENTES La declaración de componentes se realiza dentro de paquetes o en la región declarativa de una arquitectura. Es preferible declarar componentes dentro de los paquetes ya que estos son reutilizables, y por esta razón sólo se verán declaración de componentes dentro de paquetes y no en arquitecturas, aunque también sea posible. A continuación se muestra la sintaxis de declaración de componentes. SINTAXIS COMPONENT identificador PORT( senial { , senial}: modo tipo; senial { , senial}: modo tipo; senial: { , senial}: modo tipo ); END COMPONENT; EJEMPLO COMPONENT add PORT ( a, b, ci: IN std_logic; suma, co: OUT std_logic); END COMPONENT; DECLARACIÓN DE COMPONENTES CON GENÉRICOS COMPONENT identificador GENERICS( generico{ , generico }: [ modo ] tipo [ := valor ]; · · · generico{ , generico }: [ modo ] tipo [ := valor ] ); PORT( senial { , senial}: modo tipo; 46 CAPÍTULO III: SINTAXIS DEL LENGUAJE · · · senial: { , senial}: modo tipo ); END COMPONENT; EJEMPLO COMPONENT add_n GENERICS(w: integer := 8); PORT(a, b: IN bit_vector(w-1 DOWNTO 0); ci: IN bit; suma: OUT bit_vector(w-1 OWNTO 0 ); co: OUT std_logic ) ; END COMPONENT; 3.11.2 INSTANCIACIÓN DE COMPONENTES La instanciación de componentes es una instrucción concurrente que especifica la interconexión de las señales del componente dentro del diseño en el que está siendo utilizado. Existen dos formas de hacer la instanciación de componentes: por asociación de identificadores o asociación por posición. ASOCIACIÓN POR IDENTIFICADORES En este tipo de instanciación es necesario utilizar el operador de asociación "=>" para indicar como se conectan los puerto del componente con lo puertos o señales de la arquitectura en la que está siendo utilizado dicho componente. Observe que en la asociación " a => b ", "a" pertenece al componente y "b" es una señal, variable o incluso una ecuación booleana en la que intervienen objetos de datos que pertenecen de la arquitectura donde se usa el componente. etiqueta: identificador PORT MAP( puerto_componente => señal, puerto_componente => variable, puerto_componente => expresion, puerto_componente => OPEN, · · · puerto_componente => señal ); OPEN indica cuando un puerto de salida del componente no se conecta a nada. EJEMPLO ARCHITECTURE a_reg8 OF reg8 IS SIGNAL clock, reset, enable: std_logic; SIGNAL data_in: std_logic_vector(7 IEC FRANCISCO JAVIER TORRES VALLE DOWNTO 0); SIGNAL data_out: std_logic_vector(7 DOWNTO 0); BEGIN reg_1: register8 PORT MAP ( clk => clock, rst => reset, en => enable, data => data_in, q => data_out ); END a_reg8 ; ASOCIACIÓN POR IDENTIFICADORES CON GENÉRICOS etiqueta: identificador GENERIC MAP ( identificador_generico => señal, identificador_generico => variable, identificador_generico => expresión, identificador_generico => OPEN · · · identificador_generico => señal ); PORT MAP( puerto_componente => señal, puerto_componente => variable, puerto_componente => expresion, puerto_componente => OPEN, · · · puerto_componente => señal ); ASOCIACIÓN POR POSICIÓN En la asociación por posición no es necesario nombrar los puertos del componente. Sólo se colocan las señales, variables, o expresiones en el lugar donde deseamos que sean conectadas. Es importante considerar el orden en el que fueron declarados los puertos del componente porque este orden es el debemos utilizar cuando se haga la instanciación del componente. etiqueta: identificador PORT MAP ( señal, variable, OPEN, señal, variable, OPEN, ..., señal ); EJEMPLO ARCHITECTURE a_reg8 OF reg8 IS SIGNAL clock, reset, enable: std_logic; SIGNAL data_in: std_logic_vector(7 DOWNTO 0); SIGNAL data_out: std_logic_vector(7 DOWNTO 0); BEGIN reg_1: register8 PORT MAP(clock, reset, 47 CAPÍTULO III: SINTAXIS DEL LENGUAJE enable, data_in, data_out); END a_reg8; IEC FRANCISCO JAVIER TORRES VALLE 48 CAPÍTULO III: SINTAXIS DEL LENGUAJE ASOCIACIÓN POR POSICIÓN CON GENÉRICOS etiqueta: identificador GENERIC señal, variable, expresión, ..., señal); PORT MAP ( señal, variable, señal, variable, OPEN, ..., MAP( OPEN, OPEN, señal); EJEMPLO ARCHITECTURE a_sum4 OF sumador4 IS SIGNAL carry_in, carry_out: std_logic; SIGNAL x, y, z: std_logic_vector(3 DOWNTO 0); BEGIN -- add_n es el componente de ejemplo en -- "declaración de componentes con -- genéricos" u1: add_n GENERIC MAP(4); PORT MAP(x, y, carry_in, z, carry_out); END a_reg8; 3.11.3 SENTENCIAS DE GENERACIÓN Las sentencias de generación de componentes permiten crear una o más copias de un conjunto de interconexiones, lo cual facilita el diseño de circuitos mediante descripciones estructurales. • FOR.. GENERATE Esta instrucción genera un número finito de conexiones o de instrucciones concurrentes mediante rango discreto. SINTAXIS c(2*i + 1) <= a(i) NOR x; c(2*i) <= b(i) NOR x; END GENERATE; Figura 3.12 For... Generate El uso más común de las instrucciones de generación es para crear múltiples copias de componentes y procesos. En el siguiente ejemplo se muestra como utilizar estas instrucciones con componentes y en la figura 3.13 se muestra el circuito resultante. COMPONENT comp PORT (x : IN bit; y : OUT bit); END COMPONENT; · · · SIGNAL a, b: bit_vector(0 TO 7); . . . gen: FOR i IN a'RANGE GENERATE u: comp PORT MAP (x => a(i), etiqueta: FOR indice IN rango GENERATE { instucciones_concurrentes } END GENERATE; La etiqueta es necesaria y el índice de bucle es una variable del tipo entero que no necesita ser declarada anteriormente. EJEMPLO El siguiente ejemplo muestra como conectar dos arreglos de cuatro bits un tercer arreglo de ocho bits. SIGNAL a, b SIGNAL c SIGNAL x . . . genera: FOR : bit_vector(3 DOWNTO 0); : bit_vector(7 DOWNTO 0); : bit; i IN 3 DOWNTO 0 GENERATE IEC FRANCISCO JAVIER TORRES VALLE y => b(i)); 49 CAPÍTULO III: SINTAXIS DEL LENGUAJE END GENERATE gen; Figura 3.13 Instaniación de Componentes utilizando la inst. For... Generate • PROCESS(clk, s) BEGIN IF clk'EVENT AND clk='1' THEN convert(i) <= s(i-1); END IF; END PROCESS; END GENERATE; IF.. GENERATE If... Generate realiza la instrucción de instanciación o la instrucción concurrente sólo si la condición de prueba es válida. SINTAXIS etiqueta: IF condición GENERATE { instucciones_concurrentes } END GENERATE; El uso es similar a la instrucción secuencial IF... THEN, la diferencia es que en esta no se pueden utilizar la condiciones extras ELSE o ELSIF. El siguiente ejemplo muestra la descripción de un registro de conversión serieparalelo de N bits. La información serial DATA es almacenada en los registros CONVERT a través de cnexiones mediante la señal S, en cada transición positiva del reloj. El circuito resultante se muestra en la figura 3.14. -- Almacena el bit de entrada DATA en el -- primer registro g3: IF (i = convert'RIGHT) GENERATE PROCESS(clk,s) BEGIN IF clk'EVENT AND clk='1' THEN convert(i) <= data; END IF; END PROCESS; s(i) <= convert(i); END GENERATE; END GENERATE; END behavior; Como podrá observar en la figura 3.14 las retroalimentaciones en algunas ocasiones se realizaron desde la salida Q de cada registro y en otros usando la salida negada. Esto dependerá del programa de síntesis utilizado y del dispositivo empleado. ENTITY converter IS GENERIC(n: integer := 8); PORT(clk, data: IN bit; convert: BUFFER bit_vector(n-1 DOWNTO 0)); END converter; ARCHITECTURE behavior OF converter IS SIGNAL s: bit_vector(convert'RANGE); BEGIN g: FOR i IN convert'RANGE GENERATE ----- Desplaza el bit del registro (N-2) en el registro superior (N-1). Ya que el bit N-1 se pierde en cada transición del reloj. g1: IF (i = convert'LEFT) GENERATE PROCESS(clk, s) BEGIN IF clk'EVENT AND clk='1' THEN convert(i) <= s(i-1); END IF; END PROCESS; END GENERATE; -- Desplaza los bits intermedios -- hacia arriba g2: IF (i > convert'RIGHT AND i < convert'LEFT) GENERATE s(i) <= s(i-1) AND convert(i); IEC FRANCISCO JAVIER TORRES VALLE 50 CAPÍTULO III: SINTAXIS DEL LENGUAJE Figura 3.14 Diseño de circuitos utilizando la inst. If... Generate IEC FRANCISCO JAVIER TORRES VALLE 51 CAPÍTULO III: SINTAXIS DEL LENGUAJE 3.12 SUBPROGRAMAS Los subprogramas son secuencias independientes de instrucciones y declaraciones que pueden ser llamadas en repetidas ocasiones dentro de una arquitectura, proceso, o cuerpo de un paquete en VHDL. Existen dos tipos de subprogramas: procedimientos y funciones. Desde el punto de vista del hardware, un llamado a un subprograma es similar a la instanciación de un componente, con la diferencia que el subprograma forma parte del circuito en el cual esta siendo utilizado. La instanciación de un componente o módulo, implica la síntesis de dos o más niveles de jerarquía en el diseño. Un subprograma sintetizado generalmente es un único circuito combinacional (utilícese un proceso si se desea crear un circuito secuencial). Los subprogramas se declaran habitualmente en paquetes y los cuerpos de dichos subprogramas son implementados en el cuerpo del paquete en el que fueron declarados. Aunque es posible definir los subprogramas dentro de otras estructuras (arquitecturas y procesos), no es común que se haga, además, que algunos sintetizadores restringen la utilización de ellos sólo dentro de paquetes. Acerca de dichas restricciones en el uso de subprogramas, consúltese los manuales de referencia de VHDL o manuales de usuario del sintetizador que se este utilizando. 3.12.1 PROCEDIMIENTOS parámetros es un variable, entonces el procedimiento puede ser utilizado sólo secuencialmente. Recordemos que las variables solamente pueden ser declaradas dentro procesos, procedimientos y funciones y por esto un procedimiento que utilice una variable como parámetro puede ser invocado únicamente dentro del proceso en el que se encuentra declarada dicha variable. Una variable declarada dentro de un procedimiento existe solamente en el momento de ejecución del mismo, similar a la declaración de variables dentro de procesos. DECLARACIÓN DE PROCEDIMIENTOS PROCEDURE procedimiento ( lista de parámetros ); CUERPO DEL PROCEDIMIENTO PROCEDURE procedimiento (lista de parámetros ) IS -- declaraciones BEGIN -- instrucciones secuenciales END procedimiento; EJEMPLO PACKAGE ejemplo IS -- declaración de procedimiento PROCEDURE procedimiento(a: IN bit ; b: INOUT bit); END ejemplo; Un procedimiento es un algoritmo que puede regresar uno o varios valores y que, además, puede o no tener parámetros. Estos se utilizan generalmente para descomponer grandes descripciones comportamentales en pequeñas secciones, las cuales a su vez pueden ser utilizadas por distintos procesos dentro de la descripción. PACKAGE BODY ejemplo IS -- cuerpo del procedimiento PROCEDURE procedimiento ( a: IN bit ; b: INOUT bit) IS BEGIN b := a AND b ; END; END ejemplo; Los parámetros que se utilizan en el llamado de un procedimiento deben ser constantes, variables, o señales. Además, también debe especificarse el modo ya sea IN, OUT, o INOUT. A menos que se especifique, un parámetro se considera como una constante si se utiliza en el modo IN, y por omisión una variable si se utiliza el modo INOUT o OUT. 3.12.2 FUNCIONES Los procedimientos pueden ser utilizados de manera concurrente o secuencial, es decir, ya sea fuera o dentro de un proceso. Si alguno de los IEC FRANCISCO JAVIER TORRES VALLE Una función es un algoritmo que retorna un único valor y puede o no tener parámetros de entrada. Las funciones se utilizan generalmente para: (1) Convertir objetos de datos de un tipo a otro. (2) Como simples funciones que realizan operaciones para las más frecuentes situaciones de diseño. Los parámetros de una función siempre son del modo IN y deben 47 CAPÍTULO III: SINTAXIS DEL LENGUAJE ser señales o constantes. Además, cualquier variable declarada dentro de la función existe solamente dentro de la función. DECLARACIÓN DE FUNCIONES FUNCTION identificador (lista de parámetros) RETURN tipo; CUERPO DE LA FUNCIÓN FUNCTION identificador (lista de parámetros) RETURN tipo IS -- declaraciones BEGIN -- instrucciones secuenciales END identificador ; EJEMPLO FUNCTION cuenta_unos( vec1: std_logic_vector) RETURN integer IS VARIABLE temp: integer := 0; BEGIN FOR i IN vec1'low TO vec1'high LOOP IF vec1 (i) = '1' THEN temp := temp + 1; END IF; END LOOP; RETURN temp; END cuenta_unos; 3.12.3 LLAMADO A SUBPROGRAMAS Como ya mencionamos un subprograma puede tener o no tener parámetro. Además, en la declaración de un subprograma se define el nombre, modo, y tipo de dato para cada parámetro. Cuando el subprograma es llamado, cada parámetro recibe un valor. El valor que recibe el parámetro (con su tipo correspondiente) puede ser el resultado de una expresión, el valor de un variable, o de una señal. El modo en el que es declarado el parámetro especifica la forma en que puede ser utilizado, similar a los puertos en una entidad. - IN: lectura. - OUT: escritura. - INOUT: lectura y escritura. Un parámetro que es declarado en el modo OUT o INOUT debe ser una variable o una señal, ya sea para tipos simples como el bit, o arreglos como el bit_vector. Cuando el subprograma es un procedimiento, puede tener múltiples parámetros IEC FRANCISCO JAVIER TORRES VALLE que pueden utilizar los modos: IN, INOUT, o OUT. Los procedimientos son usados cuando se desea actualizar o modificar algún dato. Un ejemplo puede ser un procedimiento con un parámetro INOUT tipo bit_vector el cual invierte los bits del vector. Si por el contrario el subprograma es una función, esta puede tener múltiples parámetros, todos del modo IN. Una vez que se ejecuta la función, esta retorna un único valor. Este valor debe ser especificado con un tipo determinado. Un ejemplo es la función ABS que regresa el valor absoluto del parámetro. LLAMADO A PROCEDIMIENTOS El llamado a un procedimiento se invoca por su nombre, y este utiliza los parámetros que le son listados. SINTAXIS identificador_procedimiento( [ identificador => ] expresión { , [ identificador => ] expresión}) }; Cada expresión puede ser el identificador de una señal, variable, o alguna operación. Al igual que en la instanciación de componentes, la asociación de los parámetros puede ser por el nombre o por posiciones. EJEMPLO ENTITY proc_ejemplo IS PORT(entA: INOUT bit_vector(1 DOWNTO 0); entB: INOUT bit_vector(1 DOWNTO 0); entC: INOUT bit_vector(1 DOWNTO 0); sal0: INOUT bit_vector(1 DOWNTO 0); sal1: INOUT bit_vector(1 DOWNTO 0)); END proc_ejemplo; ARCHITECTURE ejemplo OF proc_ejemplo IS PROCEDURE procedimiento( a: IN bit_vector(1 DOWNTO 0); b: IN bit_vector(1 DOWNTO 0); c: INOUT bit_vector(1 DOWNTO 0)) IS BEGIN c := a AND b ; -- al no especificarse -- como señales los parámetros INOUT -- son variables por omisión END; BEGIN procedimiento(a =>( entA AND entC ), b => entB, c => sal0); procedimiento(entA, entC, sal1) ; END ejemplo; 48 CAPÍTULO III: SINTAXIS DEL LENGUAJE EJEMPLO El siguiente ejemplo muestra un procedimiento local (declarado dentro de un proceso) llamado SWAP el cual compara y ordena dos elementos de un arreglo. El procedimiento es llamado varias veces para acomodar todos los elementos del arreglo. PACKAGE data_types IS TYPE dat_element IS integer RANGE 0 TO 3; TYPE data_array IS ARRAY (1 TO 3) OF dat_element; END data_types; USE work.data_types.ALL; ENTITY sort IS PORT(in_array: IN data_array; out_array: OUT data_array); END sort; ARCHITECTURE example OF sort IS BEGIN PROCESS(in_array) PROCEDURE swap(data: INOUT data_array; low, high: IN integer) IS VARIABLE temp: data_element; BEGIN IF (data(low) > data(high)) THEN temp := data(low); data(low) := data(high); data(high) := temp; END IF; END swap; VARIABLE my_array: data_array; BEGIN my_array := in_array; swap(my_array, 1, 2); swap(my_array, 2, 3); swap(my_array, 1, 2); out_array <= my_array; END PROCESS; END example; LLAMADO A FUNCIONES Una función es llamada por su nombre y utiliza los parámetros que le son dados. Las funciones regresan un único valor. SINTAXIS identificador_función ( [ identificador => ] expresión { , [ identificador => ] expresión}) }; Al igual que en los procedimientos es posible especificar los parámetros mediante asociación de nombres, o asociación por posiciones IEC FRANCISCO JAVIER TORRES VALLE FUNCTION invert ( a : bit ) RETURN bit IS BEGIN RETURN ( not a ) ; END; . . . PROCESS VARIABLE v1, v2, v3: bit ; BEGIN v1 := '1'; v2 := INVERT (v1) XOR 1 ; v3 := INVERT ('0') ; END PROCESS; INSTRUCCIÓN RETURN La instrucción RETURN termina un subprograma. Si el subprograma es una función es necesario utilizar la instrucción RETURN, en el caso de los procedimientos es opcional. La sintaxis es la siguiente. RETURN expresión; -- Funciones RETURN; -- Procedimientos En una función la expresión proporciona el valor de retorno de la función. Cada función debe de tener al menos una instrucción de retorno. El tipo de datos que maneja la expresión de retorno debe coincidir con el tipo de dato de retorno declarado en la función. EJEMPLO PACKAGE ejemplo_return IS FUNCTION ejemplo_func (a, b, c: bit) RETURN bit; END ejemplo_return; PACKAGE BODY ejemplo_return IS FUNCTION ejemplo_func (a, b, c: bit) RETURN bit IS BEGIN IF (c = '1') THEN RETURN(a XOR b); ELSE RETURN NOT(a XOR b); END IF; END ejemplo_func; END ejemplo_return; LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE work.ejemplo_return.ALL; -- la librería "work" es la librería del -- presente proyecto ENTITY uso_funcion IS PORT ( SIGNAL in1, in2, in3: IN bit; SIGNAL valor_de_retorno: OUT bit); END uso_funcion; 49 CAPÍTULO III: SINTAXIS DEL LENGUAJE ARCHITECTURE funcion OF uso_funcion IS BEGIN valor_de_retorno <= ejemplo_func(in1, in2, in3); END funcion; En el siguiente ejemplo, la función OPERATE realiza las funciones AND y OR con los operandos de entrada A y B. LA operación realizada depende del valor del parámetro OPERATION. El circuito resultante se muestra en la figura 3.15. FUNCTION operate(a, b, operation: bit) RETURN bit IS BEGIN IF (operation = '1') THEN RETURN (a AND b); ELSE RETURN (a OR b); END IF; END operate; -- de datos FUNCTION "AND" (input1, input2: IN mi_bit) RETURN mi_bit; FUNCTION "OR" (input1, input2: IN mi_bit) RETURN mi_bit; · · · SIGNAL a, b, c: mi_bit; · · · c <= ( a OR b ) AND c; Cuando se sobrecarga un operador en VHDL, es necesario que el nombre del operador se encuentre entre comillas dobles " " para que el programa de síntesis lo interprete como operador. Si no se hace así entonces se considera a la función como tal y no como un operador sobrecargado. 3.13 LIBRERÍAS Una librería consiste en una colección de unidades de diseño analizadas previamente con lo cual se facilita la utilización de estas en nuevos diseño. Para incluir una librería se utiliza la siguiente sintaxis. LIBRARY identificador_librería; Figura 3.15 Circuito generado mediante el uso de funciones 3.12.4 SOBRECARGA DE OPERADORES La sobrecarga de operadores consiste en definir nuevas funciones para utilizar tipos de datos con los que no estaba definido anteriormente el operador. Así, por ejemplo el operador AND no está definido de manera predeterminada para ser utilizado con los tipos std_logic_vector, unsigned y signed. Pero dentro de los paquetes std_logic_1164, numeric_std, y numeric_bit, que es donde se definen estos tipos de datos, se sobrecarga el operador AND para poder utilizarlo con estos tipos de datos. También es posible crear operadores para ser utilizados con los tipos de datos definidos por el usuario. La cláusula LIBRARY permite utilizar la librería especificada únicamente para la unidad de diseño en la cual se declara. Una unidad de diseño es una entidad, paquete, arquitectura, o cuerpo de paquete. EJEMPLO LIBRARY mi_libreria; 3.13.1 SÍNTESIS DE LIBRERÍAS EN WARP Para sintetizar librerías en WARP de Cypress Semiconductors necesitas hacer lo siguiente: 1. – Dentro de Galaxy selecciona: File > New > Project [ Target - Library ] EJEMPLO TYPE mi_bit IS ('0', '1', 'x') ; -- tipo de datos definido por el usuario -Sobrecarga de los operadores AND y OR -- para ser utilizados con el nuevo tipo IEC FRANCISCO JAVIER TORRES VALLE 50 CAPÍTULO III: SINTAXIS DEL LENGUAJE 2. – A continuación proporcionas la información del nombre de la librería, nombre del proyecto, y localización del proyecto en disco duro. Cabe mencionar que es posible crear cualquier número de proyectos dentro del mismo directorio, y todos compilando la misma librería. Por ejemplo, podemos crear un proyecto con el nombre "multiplexores" para compilar dentro de la librería "mi_libreria" en el directorio "c:\vhdl_proj\mi_libreria". Diseñar todas las unidades de diseño deseadas dentro de esta librería y compilarlas en la misma. Después podemos otro proyecto con el nombre "comparadores" para compilar en la librería "mi_libreria" en el directorio "c:\vhdl_proj\mi_libreria". Diseñar otras unidades de diseño y compilarlas. Cuando se incluya la librería "mi_librería" en otros proyectos podemos utilizar cualquier unidad de diseño que se encuentre ya sea en el proyecto de librería "multiplexores" o en el de "comparadores". Esto es posible porque ambos proyectos se compilaron en una librería con el mismo nombre y en el mismo directorio. 3. – Después aparece un cuadro de dialogo en el cual puedes agregar archivos .vhd al proyecto de librería. Si ya los tienes, puedes copiarlos al directorio o buscarlos mediante el botón Browse... agregarlos al proyecto. Si no los tienes sólo haz click en Finalizar y posteriormente podrás crear los archivos del proyecto de librería. IEC FRANCISCO JAVIER TORRES VALLE Como ya se menciono anteriormente, en una librería puedes incluir todas las unidades de diseño que desees, siendo unidades de diseños las estructuras: ENTITY, ARCHITECTURE, PACKAGE, o PACKAGE BODY. Por lo general en los archivos de librería se utilizan paquetes. Para incluir una librería creada por el usuario en algún proyecto en particular necesitar hacer lo siguiente: 1. – Seleccionas Project > Library Manager... 2. – Dentro del cuadro de dialogo del administrador de librerías, seleccionas Assign y después haces click en el botón Add... 3. – Ahora se te pide el nombre de la librería que vas a incluir y la ruta en donde se encuentran los archivos de la librería. Por ejemplo, en Library podrías poner la librería del ejemplo anterior "mi_libreria". Y en el Path escribes la ruta del directorio donde se encuentra compilada la librería. Debes escribir toda la ruta tal y como aparece en MS-DOS. Esta librería se creo en el directorio "c:\vhdl_proj\mi_libreria", pero la librería se compilo en el directorio "c:\vhdl_proj\mi_libreria\mi_libreria" y el nombre MS-DOS del directorio es " C:\vhdl_p~1\mi_lib~1\mi_lib~1". 51 CAPÍTULO III: SINTAXIS DEL LENGUAJE RETURN tempo ; END; END swap ; -- instanciación de un paquete que se -- encuentra en el mismo proyecto USE work.swap.ALL; ENTITY swap_ent IS PORT (x:IN bit_vector(3 DOWNTO 0); y: OUT bit_vector(3 DOWNTO 0)); END swap_ent; ARCHITECTURE swap_ent OF swap_ent IS BEGIN y <= swap4(x) ; END swap_ent; 4. – Después que agregaste la librería, para incluirla basta con que escribas lo siguiente: LIBRARY mi_libreria; Una vez declarada en la descripción podrás utilizar todas las unidades de diseño que se hayan compilado en la librería. El nombre de la librería de todo proyecto que estés realizando es "work". Por lo que si deseas crear un paquete en particular en el proyecto puedes incluirlo en cualquier unidad de diseño de la siguiente manera. 3.13.2 PAQUETES Un paquete en VHDL es una colección de declaraciones que pueden ser utilizadas por otras descripciones en VHDL. Un paquete en VHDL consiste de dos secciones: la declaración del paquete y el cuerpo del paquete. Para incluir un paquete en otra descripción se sigue la siguiente sintaxis: USE libreria.identificador_paquete.ALL ; Donde identificador_paquete es el nombre del paquete que creaste en el mismo proyecto. De esta manera el paquete indicado es visible para la unidad de diseño en la cual está siendo utilizado. Mediante "ALL" indicamos que deseamos incluir todas las declaraciones de funciones, componentes, tipos de datos, subtipos de datos, procedimientos, etc. que encuentren en dicho paquete. EJEMPLO DECLARACIÓN DEL PAQUETE USE work.identificador_paquete.ALL; Crea un nuevo proyecto en WARP y en un archivo de texto copia toda la siguiente descripción. PACKAGE swap IS FUNCTION swap4(data: IN bit_vector ( 3 DOWNTO 0 ) ) RETURN bit_vector; END swap; PACKAGE BODY swap IS FUNCTION swap4 (data: IN bit_vector ( 3 DOWNTO 0 ) ) RETURN bit_vector IS VARIABLE tempo: bit_vector ( 3 DOWNTO 0 ); BEGIN tempo := data(1 DOWNTO 0)& data(3 DOWNTO 2); IEC FRANCISCO JAVIER TORRES VALLE PACKAGE identificador IS -- declaración de subprograma -- declaración de tipo de datos -- declaración de subtipos -- declaración de constantes -- declaración de señales -- declaración de componentes -- declaración de atributos -- especificación de atributos -- instrucción USE END identificador; CUERPO DEL PAQUETE PACKAGE BODY identificador IS -- declaración de subprograma -- cuerpo del subprograma -- declaración de tipo de datos 52 CAPÍTULO III: SINTAXIS DEL LENGUAJE -- declaración de subtipos -- declaración de constantes -- instrucción USE END identificador; En la declaración del paquete se hace mención de todo aquello que puede ser utilizado por otras descripciones cuando se incluye el paquete. El cuerpo del paquete proporciona definiciones y declaraciones adicionales, así como la descripción completa de funciones y procedimientos que fueron declarados previamente en el paquete. EJEMPLO PACKAGE v3_tbl IS SUBTYPE v3 IS std_logic_vector(0 TO 2); TYPE v3_array IS ARRAY(0 TO 7) OF v3; CONSTANT v3_table : v3_array := ( "000", "001", "010", "011", "100", "101", "110", "111") ; FUNCTION int2v3 (ia: integer) RETURN v3; END v3_tbl; -- convierte un entero entre 0 y 7 en un -- vector de 3 bits PACKAGE BODY v3_tbl IS FUNCTION int2v3 (ia: integer) RETURN v3 IS BEGIN RETURN v3_table(ia); END int2v3; END v3_tbl; EJEMPLO Para este ejemplo crea un proyecto para compilar la librería "mi_libreria". Crea un nuevo archivo de texto y copia la siguiente descripción en él. LIBRARY ieee; USE ieee.std_logic_1164.ALL; PACKAGE multiplexores IS COMPONENT mux_2_a_1 GENERIC(msb: integer); PORT( selec: IN std_logic; x: IN std_logic_vector (msb DOWNTO 0); y: IN std_logic_vector (msb DOWNTO 0); z: OUT std_logic_vector (msb DOWNTO 0)); END COMPONENT; END multiplexores; IEC FRANCISCO JAVIER TORRES VALLE LIBRARY ieee; USE ieee.std_logic_1164.ALL; ENTITY mux_2_a_1 IS GENERIC ( msb: integer := 3 ) ; -- debe declararse siempre un valor -- inicial para que en caso de no ser -- especificado en el momento de la -- instanciación, el componente tome un -- valor por omisión PORT(selec: IN std_logic; x: IN std_logic_vector (msb DOWNTO 0); y: IN std_logic_vector (msb DOWNTO 0); z: OUT std_logic_vector (msb DOWNTO 0)); END mux_2_a_1; ARCHITECTURE a_mux_2_a_1 OF mux_2_a_1 IS BEGIN z <= x WHEN selec = '1' ELSE y WHEN selec = '0'; END a_mux_2_a_1 ; Sintetiza el proyecto y después crea otro para utilizar el paquete anterior. Para agregar la librería a este nuevo proyecto hazlo desde el administrador de librerías. Crea un nuevo archivo de texto y copia la siguiente descripción en él. LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE mi_libreria.multiplexores.ALL; -- referencia al paquete multiplexores -- que se encuentra dentro -- de la librería "mi_libreria" ENTITY multiplexor IS PORT(a,b,c,d: IN std_logic_vector (3 DOWNTO 0); selec: IN std_logic_vector (1 DOWNTO 0); salida: OUT std_logic_vector (3 DOWNTO 0)); END multiplexor; ARCHITECTURE estructural OF multiplexor IS SIGNAL salida1: std_logic_vector (3 DOWNTO 0); SIGNAL salida2: std_logic_vector (3 DOWNTO 0); BEGIN -- instanciación del componente mux_2_a_1 u1: mux_2_a_1 PORT MAP (a, b, selec(0), salida1); u2: mux_2_a_1 PORT MAP (c, d, selec(0), salida2); u3: mux_2_a_1 PORT MAP (salida1, salida2, selec(1), salida) ; END estructural ; 53 CAPÍTULO III: SINTAXIS DEL LENGUAJE Como se mencionó al principio una librería es una colección de unidades de diseño que pueden ser incluidas es otras descripciones mediante el llamada a la respectiva librería. IEC FRANCISCO JAVIER TORRES VALLE 54 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES IV IEC FRANCISCO JAVIER TORRES VALLE DESCRIPCIÓN DE CIRCUITOS DIGITALES 54 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES 4.1 PROYECTOS EN WARP 5.0 El objetivo de este capítulo es enseñarte a crear proyectos en VHDL utilizando Warp de Cypress Semiconductors. Así como diferentes métodos prácticos para la síntesis de los circuitos digitales más comunes. Figura 4.2 3. Posteriormente debe aparecer un cuadro de dialogo como el que se muestra a continuación. Para crear un proyecto con el que quieres programar un dispositivo debes de seleccionar la segunda opción (Project [Target - Device]). PROCEDIMIENTO 1. Una vez en Windows haz click en el botón de inicio, selecciona Programas > Warp R5.0 > Galaxy. 4. Cuando selecciones la opción de Project [Target - Device] aparecerá una ventana que te pide que pongas un nombre a tu proyecto, escribe el nombre de nuevo. En el segundo cuadro de texto te pide que especifiques el directorio en donde debe de guardar tu proyecto, puedes hacer un directorio nuevo desde esa misma ventana con solo escribir el nombre, por ejemplo c:\nuevo, o puedes buscar una carpeta ya existente con la opción Browse. Cuando hayas terminado de especificar los nombres haz click en el botón de Siguiente. Figura 4.1 2. Cuando te encuentres dentro del Galaxy, selecciona File > New. Figura 4.3 5. Aparecerá una ventana con título Add Files to Project, esta ventana se usa cuando ya tienes archivos que quieres agregar a tu proyecto, pero en esta ocasión por tratarse de un proyecto totalmente nuevo no es necesario especificar nada dentro de esta ventana. Solo haz click en el botón de Siguiente. IEC FRANCISCO JAVIER TORRES VALLE 55 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES 7. Luego de lo anterior, aparecerá una ventana que te pregunta si deseas guardar tu nuevo proyecto, solo haz click en Sí. 8. Ahora ya tienes un nuevo proyecto donde se encuentra suficiente información para que el compilador te genere el archivo .jed. Pero te falta agregar el código que habrá de compilarse. Selecciona File > New > Text File, o puedes hacer click en el icono de nuevo. Escribe lo siguiente dentro del archivo de texto: library ieee; Figura 4.4 6. La siguiente ventana lleva el título de Select Target Device, esta ventana es muy importante ya que es aquí donde debes de especificar el PLD en el que vas a trabajar. Los PLD's que se usan cuando se está aprendiendo son los pequeños (generalmente 16V8, 22V8 ó 22V10), estos PLD's están en la ventana como SPLD. Haz doble click sobre este texto, te aparecerá una lista de los SPLD's más comunes, selecciona el SPLD que te interese y nuevamente aparecerá una lista donde hay varios tipos del mismo SPLD, por ejemplo PALCE16V8-10PC/PI. Esta parte es importante, ya que debes de seleccionar un SPLD que tenga un encapsulado de tipo PDIP, para que lo puedas montar en tu protoboard. En la parte inferior aparece información sobre el SPLD que te interese. Cuando escojas el SPLD adecuado haz click en Finalizar. Elige File > Save As y en la opción de Guardar en, selecciona el nombre de la carpeta que usaste en el paso número 4 (c:\nuevo). Una vez que hayas seleccionado el directorio, escribe el nombre de archivo, se sugiere el nombre nuevo, con la extensión .vhd, ya que de esta manera se especifica un archivo que contiene un código en VHDL. Luego de hacer esto, guarda tu archivo. 9. Cierra el archivo de texto. 10. Selecciona Project > Add Files, te aparecerá una ventana que debe de tener tu archivo nuevo.vhd , haz click en Add, y posteriormente en OK. Figura 4.6 Figura 4.5 IEC FRANCISCO JAVIER TORRES VALLE 11. Tu archivo de texto se ha convertido en un archivo de VHDL y está dentro de tu proyecto, todo lo que programes, será compilado en el dispositivo que especificaste. En tu ventana de proyecto (si no se encuentra abierta, la puedes activar haciendo View > Project Window) debe de aparecer un icono en forma de hoja que tiene el nombre de tu proyecto. Haz click en esta hoja y te debe de aparecer un archivo con la instrucción: library ieee; solo que ahora la palabra library está 56 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES en color azul porque es una palabra reservada. Esto demuestra que haz hecho correctamente el procedimiento. 1. Una vez que se ha creado un nuevo proyecto en Galaxy, dentro del menú Project selecciona Compiler Options. Figura 4.7 12. Si la configuración de colores es la normal, notarás que todas las palabras reservadas se muestran en color azul y los comentarios en color rojo. Ahora ya puedes comenzar a hacer tu descripción en VHDL. 4.2 SIMULACIÓN DE PROYECTOS Figura 4.8 2. Lo anterior abrirá la ventana de opciones de compilación, dentro de esta se encuentra una sección para elegir el formato de los retardos para simular el circuito Simulation—Timing Model. Aquí es donde debes de seleccionar el formato 1164/VHDL. Active - HDL de la empresa Aldec Inc. es un simulador que utiliza un archivo de post - síntesis creado por WARP. Éste es un archivo .vhd con los retardos de tiempo del código sintetizado en el dispositivo seleccionado. Este tema tiene por objetivo dar una pequeña introducción a este simulador de VHDL en las siguientes tres secciones. 1. Formato de simulación 1164/VHDL. 2. Simulación. 3. Tipos de señales de estimulación. FORMATO DE SIMULACIÓN 1164/VHDL El archivo de entrada para Active - HDL es un modelo de simulación post - síntesis generado cuando se compila un archivo .vhd en el dispositivo elegido. En WARP es posible crear archivos con diferentes formatos para simulación post - síntesis. Active - HDL requiere de un archivo con el formato de simulación IEEE - 1164 / VHDL. Para crear este archivo post - síntesis debes seguir el siguiente procedimiento. IEC FRANCISCO JAVIER TORRES VALLE Figura 4.9 3. Asegúrate que se encuentre habilitado el cuadro de Enable Testbench Output. 4.2.1 PROCESO DE SIMULACIÓN El proceso de simulación lo podemos resumir en los siguientes siete pasos. 57 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES 1. Cargar un archivo con el formato de simulación 1164/VHDL. 2. Iniciación de la simulación. 3. Agregar señales. 4. Asignar señales de estimulación. 5. Correr la simulación. 6. Observación de la simulación. 7. Guarda la simulación. 1. - CARGA DEL ARCHIVO El primer paso es abrir el programa Active-HDL Sim que normalmente se encuentra en Menu Inicio > Programas > Warp > Active-HDL Sim. Para cargar el archivo selecciona Open Vhdl dentro del Menú File. 2. - INICIACIÓN DE LA SIMULACIÓN Para iniciar la simulación, activa el simulador utilizando la opción Initialize Simulation, dentro del menú Simulation. Después abre una ventana para el análisis de señales Waveform Window, si es que no se encontrara ya una abierta.. Para crear una nueva ventana de este tipo, haz clic en el icono dentro de la barra estándar de trabajo o selecciona File > New Waveform.. 3. - AGREGANDO SEÑALES El siguiente paso es agregar señales a la ventana de análisis, para esto selecciona Add Signals...en el menú Waveform. La ventana para agregar señales aparecerá con una lista de todas las señales de entrada, salida, entrada/salida y nodos internos de conexión disponibles en el diseño. Para agregar alguna de las señales que se encuentran en esta lista basta con hacer doble clic sobre el nombre de la señal. Si deseas agregar varias señales al mismo tiempo, puedes seleccionarlas mediante la tecla control y haciendo clic sobre cada señal que deseas agregar para después hacer clic sobre el botón Add que se encuentra en la parte inferior de la ventana. Figura 4.10 Es importante mencionar que el archivo con el formato 1164/VHDL se crea en el subdirectorio vhd dentro del directorio de trabajo del proyecto una vez que éste es compilado. Si se selecciona por accidente el archivo .vhd creado por el usuario, el compilador del programa generará varios errores y no podrá ser simulado. Una vez que el archivo apropiado es cargado, se desplegarán una serie de mensajes dentro de la ventana de compilación. Uno de los mensaje que debería aparecer cuando el archivo es compilado correctamente es el siguiente: Figura 4.11 4. - TIPOS DE SEÑALES DE ESTIMULACIÓN Las señales de estimulación son utilizadas para definir diferentes impulsos a los puertos de entrada del diseño que esta siendo simulado. Para seleccionar alguno de estos tipos primero selecciona la señal y después selecciona Waveform > Stimulators..., a continuación se describe brevemente los diferentes tipos de señales de estimulación de Active-HDL Sim. -- Compile success 0 Errors 0 Warnings Analysis time: 3.0 [s]. IEC FRANCISCO JAVIER TORRES VALLE 58 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES VALOR Con este tipo de estimulador asignamos un valor constante a la señal especificada. HOTKEY Con este estimulador podemos estar cambiando el valor de la señal presionando una tecla. Cuando asignamos este tipo de estimulador es conveniente asignar una lista de valores. Cada que presionemos la tecla asignada, estaremos cambiando entre los valores de esta lista. Figura 4.12 CLOCK Sirve para definir señales de reloj definidas con los siguientes parámetros: frecuencia, valor inicial, ciclo de trabajo y tiempo de inicio. CUSTOM Un estimulador personalizado se crea editando los valores deseados en la ventana de simulación. Estado en el modo de edición, al estimulador de entrada se le puede asignar un estado bajo o un estado alto presionando '1' o '0' respectivamente. FORMULA Un estimulador del tipo formula produce una señal definida por una simple sintaxis. La señal es definida con secuencias pares de valor - tiempo. Con la componente tiempo indicamos el momento en el que la señal asume el valor especificado. La unidad del tiempo es en picosegundos. Para repetir durante un periodo especificado, se agrega el modificador -r. La sintaxis del estimulador tipo formula se muestra a continuación. <valor> <tiempo> [,<valor> <tiempo>, <valor> <tiempo>, ...] [ -r <periodo>] Para una descripción más completa de las características del simulador consulta la ayuda del programa. 5. - CORRIENDO LA SIMULACIÓN Para correr la simulación selecciona Simulation > Run. La simulación se detendrá después que la duración especificada haya sido terminada. En este momento las señales de estimulación para los puertos de entrada pueden ser alterados y producirán efectos sobre la simulación cuando esta continué. Para volver a iniciar la simulación selecciona Simulation > Restart Simulation. 6. - OBSERVANDO LA SIMULACIÓN Varias propiedades pueden ser manipuladas para mejorar la apariencia de la simulación. A continuación se describen brevemente algunas de estas propiedades. BUS La líneas individuales que forman un bus pueden ser mostradas y editadas. Para mostrarlas haz clic sobre "+" que se encuentra a junto al nombre el bus. Las señales de estimulación pueden ser asignadas a cada línea del bus o al bus completo. COLOR EJEMPLO '0000' 0 ps, '1111' 100000 ps, '0011' 200000 ps -r 300000 PREDEFINIDOS Los estimuladores predefinidos son una serie de señales tipo clock con diferentes frecuencias o señales del tipo formula que pueden ser asignados a las señales. Para agregar un nuevo estimulador a esta lista, lo puedes hacer en la misma ventana dentro del cuadro Predefined. IEC FRANCISCO JAVIER TORRES VALLE Las señales de la simulación pueden ser de diferentes colores para una mejor claridad cuando varias señales son desplegadas. Para agregar color a todas las señales visibles, selecciona Waveform > Colorize Waveforms, esto asignará diferentes colores, arbitrariamente a cada señal dentro de la ventana de simulación. Para asignar color a cada señal, haz clic con el boton derecho sobre el nombre de la señal y selecciona la opción Properties.. 59 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES ZOOM Para aumentar o reducir la escala de tiempo de la simulación, selecciona View > Zoom > In/Out/Full. BOOKMARKS Para colocar marcas sobre la ventana de simulación primero selecciona Waveform > Select Mode. Cuando este modo se encuentra seleccionado, es posible colocar marcas sobre diferentes puntos de la simulación para una rápida referencia a ciertos puntos importantes de la misma. Para colocarlas primero haz clic con el botón izquierdo en donde deseas colocar una marca, después selecciona Search > Toggle Bookmark. Utilizando Next/Previous Bookmark del mismo menú puedes cambiar entre una marca y otra dentro de la simulación. Las marcas son desplegadas como un triángulo azul sobre la escala de tiempo en la ventana de simulación. Para eliminar alguna marca selecciona Waveform > Edit Mode y después haz clic con el botón izquierdo sobre la marca que deseas eliminar. ventas de simulación abiertas. La extensión de los archivos de simulación en Active-HDL Sim es .awf. 4.3 COMPARADORES El objetivo de este tema es crear, sintetizar, y simular la descripción de circuitos comparadores de magnitud utilizando WARP. PROCEDIMIENTO 1. Primero crearemos un proyecto para el ejemplo del comparador visto en el tema 3.1.2 Antes que nada debemos crear el proyecto dentro de un directorio en el que se encontrarán todos los archivos del proyecto (.pfg, .vhd, .jed, .rpt, etc. ). Se sugiere crear primero una carpeta para todos los proyectos VHDL y dentro de esa carpeta crear otra carpeta para el presente proyecto, por ejemplo c:\vhdl_proj\comparador_1, con el nombre comparador_1. MODO DE MEDICIÓN Para entrar al modo de medición selecciona Waveform > Measurement Mode. En este modo es posible desplegar el tiempo exacto entre dos eventos de la simulación. Para obtener esta información coloca el puntero sobre una transición negativa o positiva, cuando el puntero es colocado sobre alguna transición debe cambiar a color verde, presiona el botón izquierdo sobre la transición y arrastra el puntero hasta otra transición de cualquier señal dentro de la ventana de simulación y entonces suelta el botón. La medida exacta entre estas dos transiciones se desplegara como una etiqueta entre las dos transiciones. Si la etiqueta no es mostrada o no se ve completa, amplia el alto de la fila haciendo clic con el botón derecho sobre alguna de las señales que intervienen en la medición y después selecciona Properties, dentro de la venta de propiedades aumenta la altura modificando el valor del cuadro de texto Height. Para eliminar alguna etiqueta de medición selecciona Waveform > Edit Mode, después seleciona la etiqueta y presiona suprimir 7. - GUARDANDO LA SIMULACIÓN Existen dos formas de guardar la simulación. Guardar solamente la simulación de la ventana activa o guardar todas las simulaciones de las IEC FRANCISCO JAVIER TORRES VALLE Figura 4.13 2. Seleccionaremos un 22V10 con empaquetado tipo DIP para sintetizar el código. 3. Ahora creamos un nuevo archivo de texto para editar el código (File > New > Text File). Este archivo debe ser guardado con extensión .vhd y en la misma carpeta del proyecto. Se sugiere guardarlo como: c:\vhdl_proj\comparador_1\comparador1.vhd 4. A continuación se muestra la tabla de funcionamiento de este comparador y basándose en ella haremos el código de descripción en VHDL. Primero utilizaremos el estilo de 60 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES descripción de flujo de datos, que es el mismo que se utilizó cuando se expuso el ejemplo en el tema 3.1.2. TABLA DE FUNCIONAMIENTO ENTRADAS SALIDAS x<y x_men_y '1' x<y equals '0' x<y x_may_y '0' x=y x_men_y '0' x=y equals '1' x=y x_may_y '0' x>y x_men_y '0' x>y equals '0' x>y x_may_y '1' a agregarlo al presente proyecto. Para agregarlo lo hacemos desde el menú Project y dentro de éste hacemos clic en Add Files... (Project > Add Files...). Una vez que aparece la ventana para agregar archivos al proyecto, seleccionamos el archivo comprador_1.vhd y presionamos el botón "Add". Si por error hacemos clic en la opción Add All Files, todos los archivos .vhd dentro de la carpeta del proyecto se agregaran al mismo. En este caso el único archivo .vhd que debería estar dentro de la carpeta del proyecto es comparador_1.vhd, lo cual en esta ocasión no nos afectará. En caso de que hubiera más de un archivo .vhd y no deseamos tenerlo dentro del proyecto basta con seleccionarlo en la ventana de proyecto y presionar la tecla suprimir, o también desde Project > Remove Selected Source File(s). Si la ventana de proyecto no está visible entonces seleccionamos View > Reset Docking Windows. 5. Abajo se muestra el listado del comparador correspondiente al estilo de descripción de flujo de datos. Este listado debemos editarlo dentro del archivo comparador_1.vhd. ENTITY comparador IS PORT ( x: IN bit_vector(3 DOWNTO 0); y: IN bit_vector(3 DOWNTO 0); x_may_y: OUT bit; equals: OUT bit; x_men_y: OUT bit ); END comparador; ARCHITECTURE comparador OF comparador IS BEGIN equals <= '1' WHEN x = y ELSE '0'; x_may_y <= '1' WHEN x > y ELSE '0'; x_men_y <= '1' WHEN x < y ELSE '0'; END comparador; 6. Como se puede observar no se cargó ninguna librería, y no es necesario hacerlo porque el tipo bit es un tipo predefinido en WARP y en muchos otros sintetizadores de VHDL. Por esto no necesitamos de ninguna librería para poder utilizarlo. Además, recuerde que la última declaración de puertos no lleva ; Una vez que se terminó de editar el código, procedemos a guardar los cambios en el archivo y IEC FRANCISCO JAVIER TORRES VALLE Figura 4.14 7. Una vez editado y agregado el archivo al proyecto se procede a sintetizar el código en el 22V10. Seleccionamos Compile > Project o también lo podemos hacer presionado el icono de compilación. Figura 4.15 Si el archivo tiene errores, estos aparecerán en la ventana de salida (Output Window). Dentro de "Errors & Warnings" en la ventana de salida se 61 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES muestra una lista completa de los errores así como una descripción de cada error. Para acceder rápidamente a la línea en la cual ocurrió el error, basta con hacer doble clic sobre el error e inmediatamente el programa se colocará sobre la línea en donde se encuentra dicho error. Los errores pueden ser algunos de los siguientes: omitir algún punto y coma, no escribir correctamente algún identificador, sintaxis incorrecta de las instrucciones utilizadas, o uso incorrecto de los operadores. Recordemos que VHDL es un lenguaje en el que los tipos de datos son sumamente importantes y no se pueden mezclar a menos que se utilicen las librerías adecuadas. 8. La ventana de proyecto tiene 3 modos o vistas: "Source Files View", "Hierarchy View", y "Output Files View". En la primera se muestran los archivos que se han agregado al proyecto. La "Vista de Jerarquía" es útil cuando se hacen diseños jerárquicos, ya que en esta se muestra cual es el orden de importancia que hay entre ellos. Dentro de la "Vista de Archivos de Salida" aparecen los archivos que se generaron durante la compilación, los cuales fueron creados dentro de la carpeta del proyecto. Tales archivos de salida son: .jed, .rpt y un .vhd que se encuentra dentro de la carpeta "vhd" que está en la misma carpeta del proyecto (ver tema 4.2). las ecuaciones que resultaron durante el proceso de síntesis, la asignación de pines, y un informe de utilización del dispositivo. En ocasiones es complicado realizar algunas descripciones y, aunque el código se sintetiza, durante la simulación hace algo diferente a lo que esperábamos. La función del sintetizador, en este caso WARP, es la de interpretar nuestra descripción en VHDL para generar la lógica de salida. En estos casos posiblemente la descripción no corresponde exactamente a lo que queremos. Para corregir la descripción es útil consultar las ecuaciones, ya que en estas nos podemos dar cuenta que es lo que estamos describiendo realmente. En temas posteriores se presentan algunos ejemplos en los que se exponen con más detalle este tipo de problemas. SIMULACIÓN 9. Ahora que ya hemos logrado sintetizar el código y obtenido los archivos .jed y .vhd de postsíntesis procedemos a simular la descripción. Las simulaciones las haremos en Active-HDL Sim como se explicó en tema 4.2. Podemos abrir el programa desde Galaxy desde Tools > Active-HDL Sim. Figura 4.17 10. Una vez iniciado el simulador, ahora abrimos el archivo .vhd de postsíntesis como se explica a continuación. Primero seleccionamos File > Open VHDL. Figura 4.16 En el archivo .rpt se muestra un informe de los resultados de la compilación. En éste se encuentran IEC FRANCISCO JAVIER TORRES VALLE 62 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES Figura 4.18 Para después abrir el archivo .vhd de postsíntesis, el cual debería estar (si seguiste correctamente todos los pasos) en el subdirectorio: c:\vhdl_proj\comparador_1\vhd\comparador1. vhd 7 us, 1000 8 us, 1001 9 us, 1010 10 us, 1011 11 us, 1100 12 us, 1101 13 us, 1110 14 us, 1111 15 us -r 16 us Y al bus "y" también le asignaremos un estimulador del mismo tipo con la siguiente formula. 0000 0 ns, 1111 1 us, 1110 2 us, 1101 3 us, 1100 4 us, 1011 5 us, 1010 6 us, 1001 7 us, 1000 8 us, 0111 9 us, 0110 10 us, 0101 11 us, 0100 12 us, 0011 13 us, 0010 14 us, 0001 15 us -r 16 us 13. Una vez que asignamos los estimuladores iniciamos la simulación seleccionando: Simulation > Initialize Simulation. Figura 4.19 11. Hecho lo anterior ahora agregamos las señales y/o puertos que deseamos simular. Seleccionamos Waveform > Add Signals... 14. Una vez iniciada la simulación ahora corremos la simulación. Para poder correrla existen tres opciones: correr completamente la simulación (el máximo es de 2ms+3), correrla y que se detenga en un momento especifico, o adelantar la simulación solamente por algún tiempo. Para correr la simulación completamente seleccionamos Simulation > Run. Si queremos correr la simulación y especificar un tiempo en el que debe detenerse seleccionamos Simulation > Run Until... . Para correr la simulación "por pasos" o por tiempos especificados, seleccionamos Simulation > Run For. El tiempo de paso se especifica a un lado del icono de Run For. Esta última opción es la más practica al momento de simular descripciones. Figura 4.21 Figura 4.20 Ahora seleccionamos los puertos como se explicó en el tema 4.2. En este ejercicio seleccionaremos solamente los puertos declarados en la entidad, tal y como se muestra en la figura 4.22 12. Lo siguiente es asignar señales de estimulo a los puertos de entrada. Al bus "x" le asignaremos un estimulador tipo formula usando la siguiente formula. 0000 0 ns, 0001 1 us, 0010 2 us, 0011 3 us, 0100 4 us, 0101 5 us, 0110 6 us, 0111 IEC FRANCISCO JAVIER TORRES VALLE Si deseas utilizar Run For cerciórate que el tiempo de "paso" sea de 1 us. Ya que cuando asignamos los estimuladores el valor de los buses de entrada cambia cada 1 us. Si deseas utilizar Run Until... bastara con especificar un tiempo de 32 us para observar como se comporta el ciclo de asignaciones que especificamos mediante la formula, el tiempo mínimo para comprobar todos los valores (por lo menos un ciclo) es de 16 us. 15. A continuación en la figura 4.23 se muestran los resultados de la simulación. Si seguiste correctamente todos los pasos deberías obtener algo similar a lo mostrado en la siguiente figura. 63 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES Figura 4.22 Figura 4.23 Figura 4.24 IEC FRANCISCO JAVIER TORRES VALLE 64 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES 4.4 00 a 01 b 10 c descripción de circuitos digitales utilizando WARP. De esta librería se llamó el paquete std_arith, el cual contiene muchas funciones que facilitan el uso de vectores tipo std_logic con enteros. De no haber utilizado este paquete no podríamos hacer ninguna de la comparaciones que están en la asignación condicional WHEN... ELSE. Es decir, no es posible hacer la comparación "selec = 3" porque "selec" es del tipo std_logic_vector y "3" es un número entero. El paquete std_logic_1164 contiene los tipos de datos std_logic y std_logic_vector que comúnmente utilizamos por lo que es necesario cargar el paquete para poder utilizar estos tipos, sin embargo, no contiene funciones de comparación entre tipos std_logic (o arreglos de este) y enteros. Como la librería es de propia del sintetizador, es decir, que siempre esta cargada dentro del área de trabajo del proyecto o "work", podemos llamar el paquete como se muestra a continuación. 11 d USE work.std_arith.ALL; MULTIPLEXORES En este tema el objetivo es elaborar descripciones de circuitos multiplexores utilizando los tres estilos de descripción de VHDL. PROCEDIMIENTO Para la síntesis utilizaremos un 22V10 siguiendo la siguiente tabla de funcionamiento en los tres estilos de descripción. TABLA DE FUNCIONAMIENTO selec salida SIMULACIÓN 4.4.1 DESCRIPCIÓN DE FLUJO DE DATOS LIBRARY ieee; USE ieee.std_logic_1164.ALL; LIBRARY cypress; USE cypress.std_arith.ALL ; ENTITY multiplexor IS PORT(a, b, c, d: IN std_logic_vector (3 DOWNTO 0); selec: IN std_logic_vector (1 DOWNTO 0); salida: OUT std_logic_vector (3 DOWNTO 0)); END multiplexor; Para la simulación se sugiere que asignes un estimulador tipo formula a los vectores de entrada, y al vector "selec" le asignes un estimulador tipo "HOTKEY". Una vez que agregaste las señales a la simulación, selecciona con el puntero el vector "selec", después seleccionas Waveform > Stimulators..., cuando aparezca el cuadro de estimuladores selecciona "HOTKEY" dentro de "Stimulator type", y en "Press new hotkey" escribe la letra "s" o cualquier otra. ARCHITECTURE data_flow OF multiplexor IS BEGIN salida <= a WHEN selec = 0 ELSE b WHEN selec = 1 ELSE c WHEN selec = 2 ELSE d WHEN selec = 3 ; END data_flow; El listado anterior corresponde a un multiplexor 4 a 1. El bus de salida es seleccionado mediante las señales de selección selec(1) y selec(0) (std_logic_vector es un arreglo de datos del tipo std_logic). Como habrás notado se hizo el llamado a una librería no mencionada anteriormente, la librería "cypress". Esta librería es de Cypress Semiconductors y fue desarrollada para facilitar la IEC FRANCISCO JAVIER TORRES VALLE Figura 4.25 Cada que presiones la tecla "s" el vector s estará cambiando de valor, por omisión la lista de valores de asignación incluye el '0' y el '1' solamente, en 65 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES este caso necesitamos generar valores para un vector de 2 bits. Para poder hacerlo, en el mismo cuadro de dialogo cámbiate a la sección de "Hotkeys". En esta parte aparecerán las teclas que ya han sido asignadas dentro del archivo para ser utilizadas como estimuladores, así como la lista de valores de asignación de cada tecla. Para modificar la lista de valores de la tecla "s" (la que estamos utilizando), con el puntero colócate en el cuadro de secuencia y escribe la nueva lista de valores. 4.4.2 DESCRIPCIÓN COMPORTAMENTAL LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE work.std_arith.ALL; Figura 4.26 Ahora puedes correr la simulación poco a poco utilizando Simulation > Run For, o presionando la tecla "F5". Y cada que lo desees presionas la tecla "s" para cambiar el valor del vector "selec". En la figura 4.24 se muestran los resultados de la simulación. A continuación se muestran las ecuaciones obtenidas utilizando el estilo de descripción de flujo de datos. Estas ecuaciones deben ser las mismas para cualquier estilo que utilicemos, ya que estamos describiendo el mismo multiplexor sólo que de manera diferente y esto no implica que las ecuaciones vayan a ser distintas. Cuando compiles este multiplexor, en cualquiera de los tres estilos, consulta las ecuaciones dentro del archivo .rpt y verifica que sean iguales. IEC FRANCISCO JAVIER TORRES VALLE ENTITY multiplexor IS PORT(a: std_logic_vector (3 DOWNTO 0); b: std_logic_vector (3 DOWNTO 0); c: std_logic_vector (3 DOWNTO 0); d: std_logic_vector (3 DOWNTO 0); selec: std_logic_vector (1 DOWNTO 0); salida: OUT std_logic_vector (3 DOWNTO 0)); END multiplexor; ARCHITECTURE behavorial OF multiplexor IS BEGIN PROCESS(selec, a, b, c, d) VARIABLE selec_int: integer; BEGIN selec_int := to_integer(selec); CASE selec_int IS WHEN 0 => salida <= a ; WHEN 1 => salida <= b ; WHEN 2 => salida <= c ; WHEN 3 => salida <= d ; WHEN OTHERS => NULL; END CASE; END PROCESS; END behavorial; 66 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES Dentro del proceso se hace uso de un objeto de datos del tipo variable declarado como entero. Al inicio del proceso se hace la asignación "selec_int <= to_integer ( selec ) ;", esto es para poder usar enteros en la instrucción CASE, de otra manera tendríamos que indicar todos los casos utilizando los valores naturales de un vector, es decir, "00", "01", "10", y "11" para este ejemplo. Esto es solamente para facilitar la descripción y no significa que obtengamos una mejor síntesis del código en el dispositivo. Es necesario que "selec_int" sea una variable para que se le asigne inmediatamente el valor actual del vector "selec" y estemos describiendo el correctamente el funcionamiento del multiplexor. Si quisiéramos utilizar una señal en vez de una variable tenemos que hacerlo de la siguiente manera. ARCHITECTURE behavorial2 OF multiplexor IS SIGNAL selec_int:integer; BEGIN selec_int <= to_integer( selec ); PROCESS(selec_int, a, b, c, d) BEGIN CASE selec_int IS WHEN 0 => salida <= a ; WHEN 1 => salida <= b ; WHEN 2 => salida <= c ; WHEN 3 => salida <= d ; WHEN OTHERS => NULL; END CASE; END PROCESS; END behavorial2; Si observas con cuidado podrás ver que seguimos describiendo exactamente los mismo. Tanto el procesos como la asignación son de naturaleza concurrente, por lo que selec_int tiene siempre el valor actual de selec y lo convertimos a un tipo entero para facilitar la descripción. Trata de imaginar la asignación "selec_int <= to_integer ( selec )" como un circuito combinacional cuya función es cambiar el tipo de datos con el estamos manejando el vector selec y cuya salida (selec_int) se la conectamos (piensa en señales como cables) al proceso, que viene siendo otro circuito que "procesa" la información que se le suministra y obtiene finalmente la lógica de salida. A continuación se muestra un diagrama a bloques que trata de representar lo que estamos haciendo en la arquitectura anterior (behavorial2). IEC FRANCISCO JAVIER TORRES VALLE Figura 4.27 4.4.3 DESCRIPCIÓN ESTRUCTURAL Para la descripción estructural primero debemos realizar la descripción de un multiplexor 2 a 1 para después interconectar tres de ello como se muestra en la figura siguiente. Figura 4.28 Para realizar descripciones estructurales lo recomendable es utilizar varios archivos .vhd, cada uno para una entidad o paquete en particular. Crea un proyecto para la descripción estructural del multiplexor 4 a 1. Ahora crea un nuevo archivo de texto y copia la siguiente descripción. LIBRARY ieee; USE ieee.std_logic_1164.ALL; PACKAGE multiplexor IS COMPONENT mux_2_a_1 PORT( in1: IN std_logic_vector (3 DOWNTO 0); in2: IN std_logic_vector (3 DOWNTO 0); sel: IN std_logic; out1: OUT std_logic_vector (3 DOWNTO 0)); 67 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES END COMPONENT; END multiplexor; LIBRARY ieee; USE ieee.std_logic_1164.ALL; funcionamiento. Dentro de la ventana de proyecto en la "vista de jerarquía" (Hierarchy View) aparece el orden en que los componentes están siendo utilizados dentro del diseño jerárquico. ENTITY mux_2_a_1 IS PORT (in1, in2: IN std_logic_vector (3 DOWNTO 0); sel: IN std_logic; out1: OUT std_logic_vector (3 DOWNTO 0)); END mux_2_a_1; ARCHITECTURE data_flow OF mux_2_a_1 IS BEGIN out1 <= in1 WHEN sel = '0' ELSE in2; END data_flow; Guarda este archivo como mux_2_a_1.vhd dentro de la carpeta de trabajo del proyecto. Como podrás ver estamos creando un paquete con nombre "multiplexor" el cual se agrega a la librería del proyecto work. Además se tienen que llamar las librerías que se necesiten antes del paquete y antes de la entidad. Ahora abre un nuevo archivo de texto y copia en él la siguiente descripción. -- mux_structural.vhd LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE work.multiplexor.ALL; -- llamado al paquete multiplexor que se -- encuentra en la librería -- del proyecto ENTITY multiplexor IS PORT ( a,b,c,d: IN std_logic_vector (3 DOWNTO 0); selec: IN std_logic_vector (3 DOWNTO 0); salida: OUT std_logic_vector (3 DOWNTO 0)); END multiplexor; ARCHITECTURE structural OF multiplexor IS SIGNAL salida1, salida2: std_logic_vector(3 DOWNTO 0); BEGIN u1: mux_2_a_1 PORT MAP(a, b, selec(0), salida1); u2: mux_2_a_1 PORT MAP(c, d, selec(0), salida2); u3: mux_2_a_1 PORT MAP ( salida1, salida2, selec(1), salida); END structural; Guarda este archivo como mux_structural.vhd, y agrega ambos archivos al proyecto (Proyect > Add Files...). Compila el proyecto y comprueba que las ecuaciones de salida siguen siendo las mismas ya que estamos describiendo el mismo IEC FRANCISCO JAVIER TORRES VALLE Figura 4.29 Una vez que has compilado y simulado este multiplexor utilizando los tres estilos podrás ver que no hay ninguna diferencia entre usar un estilo u otro. Lo importante es describir el mismo funcionamiento para obtener los mismo resultados. De hecho, mientras estemos describiendo exactamente lo mismo no importa el número de líneas que se hagan, porque VHDL no es un lenguaje de programación de software. 4.5 SUMADORES El diseño de circuitos aritméticos eficientes es un tema fundamental en el diseño de circuitos digitales, por lo que es importante para el diseñador estar familiarizado con las opciones disponibles en la selección de algoritmos eficientes en sus aplicaciones. Está práctica tiene por objetivo familiarizarte en el diseño de circuitos sumadores utilizando algoritmos eficientes en VHDL. 4.5.1 SUMADOR TOTAL El componente básico usado en la adición de dos operandos es conocido como "sumador total". Este sumador total representa el componente con el cual podemos formar sumadores de cualquier número de bits. A continuación se muestra la tabla de funcionamiento y la representación esquemática de un sumador total, y basándose en la tabla se hará la descripción de sumador total en VHDL, para posteriormente diseñar un circuito sumador de 4 bits utilizando un 22V10. 68 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES "10" WHEN entradas = 5 ELSE "10" WHEN entradas = 6 ELSE "11" WHEN entradas = 7; sum <= salidas(0); co <= salidas(1) ; END data_flow; Si conoces las ecuaciones del circuito también puedes utilizarlas para hacer la descripción. Figura 4.30 TABLA DE FUNCIONAMIENTO ENTRADAS a b 0 0 0 0 0 1 0 1 1 0 1 0 1 1 1 1 ci 0 1 0 1 0 1 0 1 SALIDAS co suma 0 0 0 1 0 1 1 0 0 1 1 0 1 0 1 1 LIBRARY ieee; -- full_adder.vhd USE ieee.std_logic_1164.ALL; PACKAGE adder IS COMPONENT full_adder PORT(ci: IN std_logic; a, b: IN std_logic; sum: OUT std_logic; co: OUT std_logic); END COMPONENT; END adder; LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE work.std_arith.ALL; ARCHITECTURE data_flow OF full_adder IS BEGIN sum <= a XOR b XOR C; co <= (a AND b) OR (a AND ci) OR (b AND ci); END data_flow; Crea un nuevo proyecto en c:\vhdl_proj\prac5\ y llámalo sumador. Después crea un nuevo archivo de texto y copia en él la descripción anterior. Guarda el archivo de texto como full_adder.vhd dentro de la carpeta de trabajo del proyecto. Agrega el archivo al proyecto y compila el proyecto utilizando la arquitectura data_flow. Abre el reporte de compilación y observa las ecuaciones. Ahora compila el proyecto utilizando la segunda arquitectura data_flow. Vuele a abrir el proyecto y observa las ecuaciones. ¿Por qué son las mismas ecuaciones? porque estamos describiendo el mismo funcionamiento y el estilo o el número de líneas que utilices no importa siempre y cuando este describiendo exactamente el mismo circuito. 4.5.2 SUMADOR DE CUATRO BITS Para hacer la descripción utilizaremos cuatro unidades del sumador total (u1 a u4) y las conectaremos como se muestra continuación. ENTITY full_adder IS PORT(ci: IN std_logic; a, b: IN std_logic; sum: OUT std_logic; co: OUT std_logic); END full_adder; ARCHITECTURE data_flow OF full_adder IS SIGNAL entradas: std_logic_vector (2 DOWNTO 0); SIGNAL salidas: std_logic_vector (1 DOWNTO 0); BEGIN entradas <= a&b&ci ; salidas <= "00" WHEN entradas = 0 ELSE "01" WHEN entradas = 1 ELSE "01" WHEN entradas = 2 ELSE "10" WHEN entradas = 3 ELSE "01" WHEN entradas = 4 ELSE IEC FRANCISCO JAVIER TORRES VALLE Figura 4.31 Abre un nuevo archivo de texto y copia en él la siguiente descripción. -- sumador de 4 bits utilizando -- un sumador total 69 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE work.std_arith.ALL; USE work.adder.ALL; ENTITY sumador IS PORT (ci: IN std_logic; a, b: IN std_logic_vector (3 DOWNTO 0); sum: OUT std_logic_vector (3 DOWNTO 0); co: OUT std_logic); END sumador; ARCHITECTURE structural OF sumador IS SIGNAL c1, c2, c3: std_logic; BEGIN u1: full_adder PORT MAP (ci, a(0), b(0), sum(0), c1 ) ; u2: full_adder PORT MAP (c1, a(1), b(1), sum(1), c2 ) ; u3: full_adder PORT MAP (c2, a(2), b(2), sum(2), c3); u4: full_adder PORT MAP (c3, a(3), b(3), sum(3), co); END structural; Guarda el archivo de texto en la carpeta de trabajo del proyecto (c:\vhdl_proj\prac5) como sumador.vhd. Compila el proyecto y observa lo que sucede. Si estas usando la versión 5.0 o 5.2 de WARP, la compilación te indicará los siguientes errores. Error: Logic equation has too many product terms on signal co. Error: Logic equation has too many product terms on signal sum(2). Error: Logic equation has too many product terms on signal sum(3). Abre el reporte de compilación y observa las ecuaciones. La descripción no se pudo compilar porque las ecuaciones tienen demasiadas sumas de productos. El sintetizador de WARP siempre trata de evitar retroalimentaciones para que el circuito funcione con la mayor velocidad posible. Nosotros deseamos que los nodos c1, c2, y c3 queden en un pin de salida del 22V10 para de esta forma hacer las conexiones como se muestran en el diagrama a bloques del sumador de 4 bits. Para lograrlo basta con describir la entidad como se muestra a continuación. ENTITY sumador IS PORT ( ci: IN std_logic; a, b: IN std_logic_vector (3 DOWNTO 0); sum: OUT std_logic_vector (3 DOWNTO 0); IEC FRANCISCO JAVIER TORRES VALLE co, c1, c2, c3: INOUT std_logic); END sumador; De esta forma enviamos los nodos c1, c2, y c3 a la salida de una macroceldas, en el caso del 22V10 a un pin de salida, y así evitamos que el sintetizador elimine el nodo porque ya lo declaramos como puerto. 4.5.3 SYNTHESIS OFF Otra forma de evitar que se simplifique el nodo es utilizando directivas de síntesis. En este caso utilizaremos la directiva synthesis_off que está incluida en WARP. Esta directiva nos permite controlar la forma en que el sintetizador factoriza y obtiene las ecuaciones de salida y de esta manera evitar que la ecuación de un nodo se incluya en la ecuación de otro nodo y así evitar retroalimentaciones. Para entender como funciona esta directiva observe el siguiente ejemplo. ENTITY synthesis_off IS PORT ( a, b, c: IN bit; y: OUT bit); END synthesis_off; ARCHITECTURE simplifica_nodo OF synthesis_off IS SIGNAL x: bit; BEGIN x <= a AND b; y <= x OR c; END simplifica_nodo; Cuando compilemos el archivo la ecuación del nodo "x" se sustituye en la ecuación del puerto "y" como se muestra abajo. y = a * b + c Lo que trataríamos de hacer entonces sería declara el nodo "x" como puerto y no como señal de interconexión, pero observa que es lo que sucede. x = a * b y = a * b + c La ecuación de "x" se sigue sustituyendo en la ecuación del puerto "y". Como habíamos mencionado, el sintetizador siempre busca que el circuito que le estamos describiendo funcione a la mayor frecuencia posible. Al obtener las ecuaciones de la forma anterior evitamos que exista una retroalimentación desde el pin del puerto "x", ya que si retroalimentamos tenemos que esperar el tiempo de retardo de las compuertas 70 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES que intervienen en las ecuaciones de "x" para que después el valor de "x" se incorpore a las ecuaciones del puerto "y". Por lo que el tiempo de retardo para el puerto "y" sería mayor. Sin embargo, aunque lo mejor es que nuestro circuito funcione a mayor velocidad, en ocasiones necesitamos que el nodo quede en una macrocelda para que después se retroalimente hacia otras ecuaciones. Ya sea por que lo necesitamos en el diseño del circuito o por las limitaciones del dispositivo programable. Es aquí donde las directivas de síntesis nos permiten controlar el proceso de síntesis. Observa el siguiente ejemplo en el que se muestra como utilizar la directiva synthesis_off. ENTITY synthesis_off IS PORT ( a, b, c: IN bit; y: OUT bit); END synthesis_off; ARCHITECTURE no_simplifica_nodo OF synthesis_off IS SIGNAL x: bit; ATTRIBUTE synthesis_off OF x: SIGNAL IS true; BEGIN x <= a AND b; y <= x OR c; END no_simplifica_nodo; Las ecuaciones que resultan del proceso de síntesis son las siguientes. /y = /c * /x x = a * b Ahora las ecuaciones tienen menos términos y obligamos a que el nodo "x" quede en una terminal, obligándolo a quedar en una macrocelda para que después se retroalimente. Para el circuito sumador de cuatro bits podemos utilizar esta directiva de la siguiente forma. ARCHITECTURE structural OF sumador IS SIGNAL c1, c2, c3: std_logic; ATTRIBUTE synthesis_off OF c1, c2, c3: SIGNAL IS true; BEGIN u1: full_adder PORT MAP (ci, a(0), b(0), sum(0), c1 ) ; u2: full_adder PORT MAP (c1, a(1), b(1), sum(1), c2 ) ; u3: full_adder PORT MAP (c2, a(2), b(2), sum(2), c3); u4: full_adder PORT MAP (c3, a(3), b(3), sum(3), co); END structural; IEC FRANCISCO JAVIER TORRES VALLE Esta directiva sólo puede ser aplicada a señales, para una explicación más detallada de esta y otras directivas de síntesis consulta la ayuda del programa (Help > Help Topics). Para diseño de circuitos aritméticos y no aritméticos que sean grandes o complejos, lo mejor es hacer descripciones estructurales y utilizar las directivas de síntesis cuando sea necesario. 4.6 REGISTROS Existen dos métodos para implementar lógica registrada en VHDL: mediante instanciación de registros (utilizando librerías de componentes) o utilizando procesos para realizar la descripción comportamental del registro. Por ejemplo, si se desea utilizar un registro D y un contador de 4 bits, basta con realizar la instanciación de dichos componentes después de incluir los paquetes apropiados. EJEMPLO USE work.rtlpkg.ALL; -- paquetes de WARP USE work.lpmpkg.ALL; . . . -- DSRFF: definido en rtlpkg d1: dsrff PORT MAP(d, s, r, clk, q ; -- Mcounter: definido en lpmpkg c1: Mcounter GENERIC MAP (4) PORT MAP (data, clk, one, one, one, count, zero, rst, zero, zero, zero, zero zero, zero, OPEN); Otra forma de registrar elementos es incluir un proceso que sea sensible a las transiciones de una señal de reloj o que espere una transición de reloj utilizando la instrucción WAIT, de esta manera el compilador asigna un registro a las señales afectadas dentro del proceso. Existen 4 formas básicas para describir registros, cada una de ellas se explica a continuación. PROCESS BEGIN WAIT UNTIL clk = '1'; . . . END PROCESS; Este proceso no tiene lista sensible, por lo que comienza con una instrucción WAIT. Las instrucciones dentro del proceso se comenzarán a ejecutar cuando exista una transición positiva de la 71 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES señal de reloj "clk". Todas las asignaciones a señales dentro del proceso serán registradas, ya que estas sólo cambian de valor en las transiciones de reloj y lo retienen por lo menos hasta la siguiente transición. PROCESS (clk) BEGIN IF ( clk'event AND clk ='1' ) THEN . . . END IF; END PROCESS; Este proceso es sensible solamente a los cambios en la señal "clk", como se indica en la lista sensible. La primera instrucción, IF... THEN, dentro del proceso restringe al resto de las instrucciones a ser ejecutadas únicamente durante la transición positiva de la señal "clk", por lo que ahora también todas las señales que reciban una asignación dentro de la instrucción IF... THEN serán registradas y mantendrán dicho valor recibido por lo menos hasta la siguiente transición de reloj. PROCESS(rst, clk) BEGIN IF rst = '1' THEN . . . ELSIF(clk'event AND clk='1') THEN . . . END IF; END PROCESS; Este proceso es sensible a los cambios en la señal de reloj "clk" y la señal de reinicio "rst", como es indicado en la lista sensible. Mediante este método de descripción comportamental es posible registrar señales y además tener un "reset" asíncrono. La primera instrucción checa primero el estado de la señal "rst". Las señales que son asignadas dentro de esta porción de la estructura IF... THEN... ELSIF, se asume que son registradas asíncronamente con la señal de "reset" asignada, y serán sintetizadas en registros con capacidad para realizar dicha acción. Si la condición de "reset" no se cumple, el resto de la instrucción IF... THEN... ELSIF, funciona como el proceso explicado anteriormente. PROCESS(rst, pst, clk) BEGIN IF rst = '1' THEN . . . ELSIF pst = '1' THEN . . . ELSIF (clk'event AND clk='1') THEN IEC FRANCISCO JAVIER TORRES VALLE . . . END IF; END PROCESS; Este proceso es sensible a los cambios en la señales "clk", "rst" y "pst", como se indica en la lista sensible. De esta forma es posible realizar la descripción de registros con "preset" y "reset" asíncronos. La primera instrucción dentro del proceso checa el estado de la señal "rst". Todas las señales que son asignadas dentro de la primera porción de la estructura, se asume que serán registradas mediante la señal de "rst" asíncrono. La segunda condición checa el estado de la señal "pst", y todas las señales que sean asignadas dentro de esta porción del proceso son registradas asíncronamente mediante la señal de "preset" asíncrono "pst". Si las dos primeras condiciones no se cumplen, el resto de la instrucción IF... THEN... ELSIF, representa el funcionamiento síncrono del registro. EJEMPLO A continuación se muestra una forma de realizar la descripción de un registro de 32 bits con "reset" asíncrono. PROCESS(r, clk2) BEGIN IF (r = '1') THEN q <= x"123DEABC" ; ELSIF (clk2'event AND clk2='1') THEN q <= d; END IF; END PROCESS; Asumiendo que "q" y "d" son declarados como señales o puertos de 32 bits, entonces este código ejemplifica la implementación de un registro de 32 bits con d(i) como entrada, q(i) como salida, "clk2" como la señal de reloj, y "r" como la señal de "reset" asíncrono para algunos registros y también como señal de "preset" asíncrono para otros. Esto significa que cuando se cumple la condición: r = '1', la asignación q <= x"ABC123DE" provocará que algunos registros sean puestos en alto mientras que otros van a quedar en un estado de cero lógico. EJEMPLOS A continuación realice la descripción de los siguientes registros de acuerdo con su tabla de funcionamiento. 72 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES REGISTRO NO. 1 Elabore la descripción del registro utilizando un 22V10 y posteriormente trate de implementar la descripción en un 16V8, simule la descripción y obtenga sus conclusiones. TABLA DE FUNCIONAMIENTO ENTRADAS reset d SALIDAS clk q 1 0 transición positiva 0 1 1 transición positiva 1 0 - 0 - ENTITY reg1 IS PORT(reset: IN bit; d: IN bit; clk: IN bit; q: OUT bit); END reg1; ARCHITECTURE areg2 OF reg2 IS BEGIN PROCESS(clk, reset, d) BEGIN IF clk'event AND clk = '1' THEN IF reset = '0' THEN q <= '0'; ELSE q <= d; END IF; END IF; END PROCESS; END areg2; REGISTRO NO. 3 Elabore la descripción del siguiente registro utilizando un 22V10, simule la descripción y obtenga sus conclusiones. TABLA DE FUNCIONAMIENTO ENTRADAS enable d ARCHITECTURE areg OF reg1 IS BEGIN PROCESS(clk, reset, d) BEGIN IF reset = '0' THEN q <= '0'; ELSIF clk'event AND clk = '1' THEN q <= d; END IF; END PROCESS; END areg; REGISTRO NO. 2 Elabore la descripción del registro utilizando un 22V10 y posteriormente utilice un 16V8, simule la descripción en ambos casos y obtenga sus conclusiones. SALIDAS clk q 1 0 transición positiva 0 1 1 transición positiva 1 0 - Z - LIBRARY ieee; USE ieee.std_logic_1164.ALL; ENTITY reg2 IS PORT(enable: IN std_logic; d: IN std_logic; clk: IN std_logic; q: OUT std_logic); END reg2; ARCHITECTURE areg2 OF reg2 IS SIGNAL q_tmp: std_logic; BEGIN TABLA DE FUNCIONAMIENTO ENTRADAS reset d clk SALIDAS q 1 0 transición positiva 0 1 1 transición positiva 1 0 - transición positiva 0 ENTITY reg2 IS PORT(reset, d,clk: IN bit; q: OUT bit); END reg2; IEC FRANCISCO JAVIER TORRES VALLE -- lógica registrada PROCESS(clk, reset, d) BEGIN IF clk'event AND clk = '1' THEN q_tmp <= d; END IF; END IF; END PROCESS; -- buffer q <= q_tmp WHEN enable = '1' g 'Z'; END areg2; 73 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES 4.7 CONTADORES La finalidad de un contador es computar el número de ocurrencias de un evento que se da en intervalos aleatorios o uniformes. En los siguientes ejemplos se muestran diferentes tipos de contadores y la forma más común de describir su comportamiento con VHDL. EJEMPLOS LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE ieee.numeric_std.ALL; ENTITY counter IS PORT( clk, load: IN std_logic; data: IN unsigned(3 DOWNTO 0); count: BUFFER unsigned(3 DOWNTO 0)); END counter; ARCHITECTURE archcounter OF counter IS BEGIN PROCESS( clk, load, count, data ) BEGIN IF( clk'event AND clk= '1' ) THEN IF load = ’1’ THEN count <= data; ELSE count <= count + 1; END IF; END IF; END PROCESS; END archcounter; La instrucción USE ieee.numeric_std.ALL es para incluir el tipo de datos unsigned, así como las funciones aritméticas y lógicas que nos permiten manipular objetos de datos que manejen este tipo. En este ejemplo en particular nos interesa la función "+" definida para ser utilizada con el tipo unsigned y enteros. Ya que el operador "+" en VHDL originalmente está definido únicamente para ser utilizado con enteros. La arquitectura que describe al contador utiliza el estilo comportamental. En este diseño el contador funciona ascendentemente y, además, realiza carga paralela de datos síncronamente con la señal de reloj dependiendo del valor del puerto de control "load". Dentro del proceso, la instrucción IF ( clk’event AND clk= ’1’ ) THEN... implica que el funcionamiento del contador, conteo y carga paralela, tome lugar durante la transición positiva de la señal de reloj "clk". La siguiente instrucción IF... THEN... define la operación de conteo o de carga paralela del circuito dependiendo de la condición: load = '1'. A continuación se expone un contador similar pero con reset síncrono. IEC FRANCISCO JAVIER TORRES VALLE LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE ieee.numeric_std.ALL; ENTITY counter IS PORT (clk, load, reset: IN std_logic; data: IN unsigned(3 DOWNTO 0); count: BUFFER unsigned(3 DOWNTO 0)); END counter; ARCHITECTURE archcounter OF counter IS BEGIN PROCESS(clk, reset, load, count, data) BEGIN IF ( clk’event AND clk= '1' ) THEN IF reset = '1' THEN count <= (OTHERS => '0'); ELSIF load = '1' THEN count <= data; ELSE count <= count + 1; END IF; END IF; END PROCESS; END archcounter; En este ejemplo se describe un contador ascendente, con reset síncrono dependiendo de la entrada "reset", además, con capacidad de carga paralela de datos mediante el puerto de control "load". Al igual que el ejemplo anterior, la instrucción IF (clk'event AND clk = '1' ) aparece al principio e implica que todas las operaciones del contador se ejecuten durante la transición positiva de la señal de reloj "clk". La subsecuente instrucción IF describe la operación de reset síncrono durante la transición positiva del reloj. El resto de las operaciones, el conteo y la carga paralela, son descritas en las siguientes cláusulas ELSIF y ELSE dentro de la misma instrucción IF, por lo que podemos observar que la operación de reset tiene precedencia sobre las operaciones de carga y conteo. Así, si reset no es '1', entonces la operación de conteo depende de la señal "load". Como podemos ver las operaciones de carga y conteo son identificas al contador en el ejemplo anterior. Ahora se expone a continuación un contador con reset asíncrono y con capacidad para salida en alta impedancia. LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE ieee.numeric_std.ALL; ENTITY cnt_oe IS PORT(clk, reset, oe: IN std_logic; count_io: INOUT std_logic_vector (7 DOWNTO 0)); 74 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES END ldcnt; 1 0 ARCHITECTURE arch_cnt_oe OF cnt_oe IS SIGNAL count: std_logic_vector (7 DOWNTO 0); BEGIN PROCESS(clk, reset, count) BEGIN IF reset = '0' THEN count <= (OTHERS => '0'); ELSIIF ( clk’event AND clk=’1’ ) THEN count <= count + 1; END IF; END PROCESS; count_io <= count WHEN oe = ’1’ ELSE (OTHERS => 'Z'); END arch_cnt_oe; 0 - Este diseño desempeña un contador ascendente con reset asíncrono. Cuando se cumple la condición: reset = '0', se produce un reset asíncrono en el contador. Cuando esta condición no se satisface, la operación de conteo funciona síncronamente con la señal de reloj "clk". Además, independientemente de las señal de reset, el uso de los buffers de tres estados en los pines de I/O es posible mediante el uso del puerto de entrada "oe". Así, cuando se satisface la condición oe = '1', el conteo es conducido hacia los pines de salida. De lo contrario presentarán alta impedancia en los pines del circuito. Conceptualmente, el código en VHDL del contador se implementa de la siguiente manera. Figura 4.32 A continuación se elabore la descripción en VHDL para los siguientes contadores de cuatro bits de acuerdo a su tabla de funcionamiento y posteriormente realice las simulaciones. Elija el dispositivo que más convenga. CONTADOR NO. 1 ENTRADAS reset up_down 1 1 SALIDAS clk conteo transición positiva ascendente IEC FRANCISCO JAVIER TORRES VALLE transición positiva descendente - 0 ENITTY counter IS PORT(reset: IN bit; ud: IN bit; clk: IN bit; conteo: INOUT integer RANGE 0 TO 15 ); END counter; ARCHITECTURE counter OF counter IS BEGIN PROCESS(reset,ud,clk) BEGIN IF reset = '1' THEN conteo <= 0; ELSIF (clk'event AND clk = '1') THEN IF ud = '1' THEN conteo <= conteo + 1; ELSE conteo <= conteo - 1; END IF; END IF; END counter; CONTADOR NO. 2 ENTRADAS reset up_down clk SALIDAS conteo 1 1 transición positiva ascendente 1 0 transición positiva descendente 0 - transición positiva 0 ENITTY counter IS PORT(reset: IN bit; ud: IN bit; clk: IN bit; conteo: INOUT integer RANGE 0 TO 15 ); END counter; ARCHITECTURE counter OF counter IS BEGIN PROCESS(reset,ud,clk) BEGIN IF (clk'event AND clk = '1') THEN IF reset = '1' THEN conteo <= 0; ELSIF ud = '1' THEN conteo <= conteo + 1; ELSE conteo <= conteo - 1; END IF; END IF; END counter; 75 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES CONTADOR NO. 3 ENTRADAS reset oe up_down SALIDAS clk conteo 1 1 1 transición positiva ascendente 1 1 0 transición positiva descendente 0 1 - - 0 0 0 - - Z ** NOTA Aunque se encuentre la salida del circuito en alta impedancia, el conteo y reset asíncrono deben seguir funcionando internamente. LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE ieee.numeric_std.ALL; ENITTY counter IS PORT(reset: IN std_logic; ud: IN std_logic; oe: IN std_logic; clk: IN std_logic; conteo: INOUT unsigned (3 DOWNTO 0) ); END counter; ARCHITECTURE counter OF counter IS SIGNAL count_tmp: unsigned(3 DOWNTO 0); BEGIN PROCESS(reset,ud,clk) BEGIN IF reset = '1' THEN count_tmp <= (OTHERS => '0'); ELSIF (clk'event AND clk = '1') THEN IF ud = '1' THEN count_tmp <= count_tmp + 1; ELSE count_tmp <= count_tmp - 1; END IF; END IF; -- instanciación de los buffers conteo <= count_tmp WHEN oe = '1' ELSE (OTHERS 'Z'); END counter; CONTADOR NO. 4 ENTRADAS reset oe up_down 1 1 1 SALIDAS clk conteo transición positiva ascendente 0-9 IEC FRANCISCO JAVIER TORRES VALLE 1 1 0 transición positiva descendente 9-0 0 1 - - 0 0 0 - - Z ** NOTA Aunque se encuentre la salida del circuito en alta impedancia, el conteo y reset asíncrono deben seguir funcionando internamente. En el momento de cambio de sentido ascendente/descendente, el contador no debe de iniciar la cuenta, por ejemplo: si el contador está funcionando ascendentemente y se encuentra en el número 5 cuando se cambia a descendente, en la siguiente transición positiva se debe continuar la cuenta con un 4, después un 3... etc. LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE ieee.numeric_std.ALL; ENITTY counter IS PORT(reset: IN std_logic; ud: IN std_logic; oe: IN std_logic; clk: IN std_logic; conteo: INOUT unsigned (3 DOWNTO 0) ); END counter; ARCHITECTURE counter OF counter IS SIGNAL count_tmp: unsigned(3 DOWNTO 0); BEGIN PROCESS(reset,ud,clk) BEGIN IF reset = '1' THEN count_tmp <= (OTHERS => '0'); ELSIF (clk'event AND clk = '1') THEN IF ud = '1' THEN count_tmp <= count_tmp + 1; IF count_tmp = 9 THEN count_tmp <= (OTHERS => '0'); END IF; ELSIF ud = '0' THEN count_tmp <= count_tmp - 1; IF count_tmp = 0 THEN count_tmp <= "1001"; END IF; END IF; END IF; -- instanciación de los buffers conteo <= count_tmp WHEN oe = '1' ELSE (OTHERS 'Z'); END counter; 76 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES 4.8 ALU DE CUATRO BITS Realice la descripción en VHDL para la siguiente unidad aritmético - lógica de acuerdo a la tabla de funcionamiento utilizando un 22V10. El circuito consta de 2 bus de entrada "a" y "b", de 4 bits cada uno y mediante el bus "s", de 3 bits, se selecciona la operación a realizar en la ALU. Dicha operación se realiza combinacionalmente y en el momento que ocurre una transición positiva en la señal de reloj el resultado de dicha operación se registra en los flip-flop's tipo D del 22V10. Además, la salida registrada será conducida hacia los pines de salida (I/O pads) únicamente cuando se habiliten los buffers de tres estados mediante la entrada de control "oe", de lo contrario deberán encontrarse en alta impedancia. ENTRADAS s(2) s(1) s(0) clk SALIDAS oe output cout 0 0 0 transición positiva 0 a AND b 0 0 0 1 transición positiva 0 a OR b 0 0 1 0 transición positiva 0 a XOR b 0 0 1 1 transición positiva 0 NOT a 0 1 0 0 transición positiva 0 a+0 0 1 0 1 transición positiva 0 a+b acarreo de la suma 1 1 0 transición positiva 0 a + b' acarreo de la suma 1 1 1 transición positiva 0 a-1 0 - - - - 1 Z 0 ** NOTA b' = NOT b 4.8.1 DESCRIPCIÓN ESTRUCTURAL La descripción se realiza utilizando tres archivos, los cuales contienen: la entidad TOP, el módulo y el paquete respectivamente. El módulo realiza todas las operaciones dela ALU pero IEC FRANCISCO JAVIER TORRES VALLE solamente con un bit, y en la entidad TOP se realiza la interconexión de cuatr de estos módulos para formar la ALU de cuatro bits. ENTIDAD TOP LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE work.modulo_alu.ALL; ENTITY alu IS PORT(a: IN std_logic_vector(3 DOWNTO 0); b: IN std_logic_vector(3 DOWNTO 0); cin: IN std_logic ; clk: IN std_logic ; reset: IN std_logic ; oe: IN std_logic ; s: IN std_logic_vector(2 DOWNTO 0); cout: OUT std_logic; output: OUT std_logic_vector(3 DOWNTO 0) ); END alu ; ARCHITECTURE a_alu OF alu IS SIGNAL c2, c3, c4: std_logic; SIGNAL salida_r: std_logic_vector (3 DOWNTO 0); ATTRIBUTE synthesis_off OF c2, c3, c4: SIGNAL IS true; BEGIN x0: modulo PORT MAP(a(0), b(0), cin, clk, reset, s, c2, salida_r(0)); x1: modulo PORT MAP(a(1), b(1), c2, clk, reset, s, c3, salida_r(1)); x2: modulo PORT MAP(a(2), b(2), c3, clk, reset, s, c4, salida_r(2)); x3: modulo PORT MAP(a(3), b(3), c4, clk, reset, s, cout, salida_r(3)); -- instanciación de los biffers output <= (OTHERS=>'Z') WHEN oe='1' ELSE salida_r; END a_alu; MÓDULO LIBRARY ieee ; USE ieee.std_logic_1164.ALL; ENTITY modulo IS PORT (in1: IN std_logic; in2: IN std_logic; cin: IN std_logic; clk: IN std_logic; reset: IN std_logic; selec: IN std_logic_vector(2 DOWNTO 0); cout: OUT std_logic ; salida_r: INOUT std_logic); END modulo; ARCHITECTURE a_modulo OF modulo IS SIGNAL salida_comb: std_logic ; BEGIN PROCESS(in2, in1, selec, cin) 77 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES CONSTANT uno: std_logic := '1'; BEGIN CASE selec IS WHEN o"0" => salida_comb <= in1 AND in2; cout <= '0'; WHEN o"1" => salida_comb <= in1 OR in2; cout <= '0'; WHEN o"2" => salida_comb <= in1 XOR in2; cout <= '0'; WHEN o"3" => salida_comb <= NOT in1; cout <= '0'; WHEN o"4" => salida_comb <= in1; cout <= '0' ; WHEN o"5" => salida_comb<=in2 XOR in1 XOR cin; cout <= ( in1 AND cin ) OR ( in2 AND cin ) OR ( in2 AND in1 ); WHEN o"6" => salida_comb<= (NOT in2) XOR in1 XOR cin; cout <= (in1 AND cin) OR (( NOT in2 ) AND cin) OR (( NOT in2 ) AND in1); WHEN o"7" => salida_comb<=uno XOR in1 XOR cin; cout <= ( in1 AND cin) OR (uno AND cin ) OR ( uno AND in1 ) ; WHEN OTHERS => NULL; END CASE; END PROCESS; PROCESS( salida_comb, clk, reset ) BEGIN IF rising_edge( clk ) THEN salida_r <= salida_comb; END IF; END PROCESS; END a_modulo; PAQUETE LIBRARY ieee; USE ieee.std_logic_1164.ALL; PACKAGE modulo_alu IS COMPONENT modulo PORT(in1: IN std_logic; in2: IN std_logic ; cin: IN std_logic ; clk: IN std_logic ; reset: IN std_logic ; selec: IN std_logic_vector(2 DOWNTO 0); cout: OUT std_logic ; salida_r: INOUT std_logic ) ; END COMPONENT; END modulo_alu; IEC FRANCISCO JAVIER TORRES VALLE 4.8.2 DESCRIPCIÓN COMPORTAMENTAL LIBRARY ieee ; USE ieee.std_logic_1164.ALL; USE ieee.numeric_std.ALL; ENTITY aluIS PORT (in1: IN unsigned(3 DOWNTO 0); in2: IN unsigned(3 DOWNTO 0); cin, clk: IN std_logic; oe: IN std_logic; reset: IN std_logic; selec: IN integer RANGE 0 TO 7; cout: OUT std_logic ; salida: INOUT unsigned(3 DOWNTO 0); ); END alu; ARCHITECTURE alu OF alu IS SIGNAL comb, reg: unsigned(3 DOWNTO 0); SIGNAL c: unsigned(4 DOWNTO 0); SIGNAL c1,c2,c3 ATTRIBUTE synthesis_off OF c1, c2, c3: SIGNAL IS true BEGIN c(0) <= cin; cout <= c(4); c1 <= c(1); c2 <= c(2); c3 <= c(3); PROCESS(in2, in1, selec, cin) CONSTANT uno: unsigned:= "0001"; BEGIN FOR i IN in1'range LOOP CASE selec IS WHEN 0 => comb(i) <= in1(i) AND in2(i); c(i+1) <= '0'; WHEN 1 => comb(i) <= in1(i) OR in2(i); c(i+1) <= '0'; WHEN 2 => comb(i) <= in1(i) XOR in2(i); c(i+1) <= '0'; WHEN 3 => comb(i) <= NOT in1(i); c(i+1) <= '0'; WHEN 4 => comb(i) <= in1(i); c(i+1) <= '0' ; WHEN 5 => comb(i) <= in2(i) XOR in1(i) XOR c(i); c(i+1) <= (in1(i) AND c(i)) OR (in2(i) AND c(i)) OR (in2(i) AND in1(i); WHEN 6 => comb(i) <= (NOT in2(i)) XOR in1(i) XOR c(i); c(i+1) <= (in1(i) AND c(i)) OR ((NOT in2(i)) AND c(i)) OR ((NOT in2(i)) AND in1(i)); WHEN 7 => comb(i) <= uno(i) XOR in1(i) XOR c(i); c(i+1) <= (in1(i) AND c(i)) OR 78 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES (uno(i) AND c(i)) OR (uno(i) AND in1(i)) ; 1. Este registro es un conjunto de n flip-flops sincronizados con la misma señal de reloj para almacenar el estado presente en la máquina. WHEN OTHERS => NULL; END CASE; END LOOP; END PROCESS; PROCESS( comb, clk, reset ) BEGIN IF rising_edge( clk ) THEN reg <= comb; END IF; END PROCESS; 2. LÓGICA COMBINACIONAL PARA GENERAR EL SIGUIENTE ESTADO. 3. Una máquina de estados solamente puede estar en un estado a un tiempo dado, es decir no puede hacer dos cosas a la vez. La lógica combinacional permite que en cada transición activa del reloj, la máquina vaya de un estado a otro o se mantenga en el mismo dependiendo de las condiciones definidas por el diseñador. 4. LÓGICA COMBINACIONAL DE SALIDA. salida <= reg WHEN oe = '0' ELSE (OTHERS => 'Z'); cout <= '0' WHEN selec = 7 ELSE c(4); END alu;s 4.9 REGISTRO DEL ESTADO PRESENTE. MÁQUINAS DE ESTADO Una máquina de estados es un circuito secuencial que es diseñado para seguir un patrón de funciones previamente definidas. Existen dos tipos de máquinas de estado: Mealy y Moore. En una máquina de estados de Moore, las salidas están únicamente en función del estado presente. Si es una máquina de estados de Mealy, las salidas están en función del estado presente y de las entradas. Una máquina de estados se compone de tres partes: Las salidas normalmente están en función del estado presente y/o también en función de las entradas (Máquina de Estados de Mealy). Es común que en una máquina de estados de Moore se desee que las salidas estén en función del siguiente estado en vez de utilizar el actual cuando se utiliza una señal de reloj de alta frecuencia. A continuación se muestran las estructuras para máquinas de estados de Moore y Mealy Figura 4.33 Máquina de Estados de Moore Figura 4.34 Máquina de Estados de Mealy IEC FRANCISCO JAVIER TORRES VALLE 79 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES El uso del reset garantiza un comportamiento seguro del circuito. Esto asegura que la máquina siempre comience en un estado conocido y válido antes de la primera transición de reloj. Si no se utiliza el reset, no existe una forma de predecir el valor inicial de los flip-flops del registro de estado durante el encendido del dispositivo en el que se implementa la máquina de estados. Además existe la posibilidad de que la máquina comience en un estado no válido y entonces nunca comenzaría a funcionar. Por lo que el reset siempre debe ser implementado en una máquina de estados para asegurar un correcto funcionamiento. Se prefiere el uso de reset asíncrono sobre el síncrono porque un reset asíncrono no requiere ser implementado mediante ecuaciones, minimizando la lógica combinacional del circuito. A continuación se muestran las tres formas más comunes de codificar los estados en una máquina, suponiendo que utiliza ocho estados: ESTADOS SECUENCIA BINARÍA ONE HOT ENCODIG SECUENCIA GRAY S0 000 00000001 000 S1 001 00000010 001 S2 010 00000100 011 S3 011 00001000 010 S4 100 00010000 110 S5 101 00100000 100 S6 110 01000000 101 S7 111 10000000 111 Cuando se implementa una máquina de estados en un FPGA se prefiere la codificación ONE HOT ENCODING porque estos dispositivos cuentan con bastantes flip-flops y una máquina de estados codificada de esta manera es más IEC FRANCISCO JAVIER TORRES VALLE eficiente y las herramientas de síntesis generan circuitos con área optimizada y mejor desempeño. Aunque también es posible que el usuario asigne los valores de los estado como mejor convenga. 80 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES EJEMPLO Figura 4.35 Diagrama de Estados -- Máquina de Estados del tipo Mealy LIBRARY ieee; USE ieee.std_logic_1164.ALL; ENTITY mealy IS PORT ( clk: IN std_logic; reset: IN std_logic; entradas: IN std_logic_vector (3 DOWNTO 0); salidas: OUT std_logic_vector (3 DOWNTO 0)) ; END mealy; ARCHITECTURE comportamental OF mealy IS -- ONE HOT ENCODED state machine TYPE states IS (S0, S1, S2, S3, S4); ATTRIBUTE enum_encoding OF states: TYPE IS "00001 " & -- S0 -- atributo de WARP "00010 " & -- S1 "00100 " & -- S2 "01000 " & -- S3 "10000" ; -- S4 SIGNAL state, next_state: states ; BEGIN -- registro del estado presente PROCESS(clk, reset) BEGIN IF reset='0' THEN IEC FRANCISCO JAVIER TORRES VALLE state <= S0; ELSIF clk'event and clk = '1' THEN state <= next_state ; END IF; END PRCESS; -- lógica combinacional para definir el -- siguiente estado PROCESS(entradas, state) BEGIN CASE state IS WHEN S0 => IF entradas = "0001" THEN next_state <= S1; END IF; WHEN S1 => IF entradas = "1001" THEN next_state <= S1; ELSIF entradas <= "1011" THEN next_state <= S4; ELSIF entradas = "0101" THEN next_state <= S2; END IF; WHEN S2 => IF entradas = "0111" THEN next_state <= S1; ELSIF entradas = "0010" THEN next_state <= S2 ; 79 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES ELSIF entradas = "1100" THEN next_state <= S3; END IF; WHEN S3 => IF entradas = "0101" THEN next_state <= S4; END IF; WHEN S4 => IF entradas = "0011" THEN next_state <= S2; ELSIF entradas = "0100" THEN next_state <= S3; ELSIF entradas = "0110" THEN next_state <= S4; ELSIF entradas = "1110" THEN next_state <= S0 ; END IF; WHEN OTHERS => NULL; END CASE; END PROCESS; -- lógica combinacional de salida salidas <= "1000" WHEN (state= S1) ELSE "0110" WHEN (state=S1 AND entradas="1001") ELSE "1100" WHEN (state=S2) ELSE "0000" WHEN (state= S2 AND entradas="0010") ELSE "0011" WHEN (state=S3) ELSE "0111" WHEN (state=S4) ELSE "0101" WHEN (state= S4 AND entradas="0110") ELSE "1011"; -- asignación en el estado de -- reset S0 END comportamental; EJEMPLO Elabore la descripción en VHDL del siguiente problema mediante máquina de estados definiendo su diagrama de estados, frecuencia de trabajo y dispositivo a utilizar. Se desea diseñar el circuito de control para lavadora de la siguiente figura. Figura 4.36 El ciclo de lavado es de la siguiente manera: 1. - Suponiendo que esta vacía al principio, cuando se presione el botón de "INICIO", activo en ALTO, se enciende la válvula de agua fría. 2. - En el momento que el nivel del agua llegue al SENSOR, activo en ALTO, se apaga la válvula de agua fría y se enciende la de agua caliente durante dos minutos. 3. - Después se apaga la válvula de agua caliente y se enciende el motor durante cuatro minutos. 4. - Transcurridos los cuatro minutos, se apaga el motor y se enciende la válvula de desagüe durante tres minutos. 5. - Una vez que se ha vaciado la lavadora se cierra la válvula de desagüe y el ciclo de lavado comenzará nuevamente cuando se vuelva a presionar el botón de inicio. LIBRARY ieee; USE ieee.std_logic_1164.ALL; ENTITY lavadora IS PORT( clk: IN std_logic; inicio: IN std_logic; sensor: IN std_logic; vaf: OUT std_logic; vac OUT std_logic; motor: OUT std_logic; des: OUT std_logic ); END lavadora; ARCHITECTURE state_machine OF lavadora IS TYPE states IS (S0,S1,S2,S3,S4,S5,S6,S7,S8,S9,S10); SIGNAL state, nex_state: states; SIGNAL outputs: std_logic_vector (3 DOWNTO 0); CONSTANT vaf_on: std_logic_vector (3 DOWNTO 0):="0001"; CONSTANT vac_on: std_logic_vector (3 DOWNTO 0):="0010"; CONSTANT mot_on: std_logic_vector (3 DOWNTO 0):="1000"; CONSTANT des_on: std_logic_vector (3 DOWNTO 0):="0100"; CONSTANT all_off: std_logic_vector (3 DOWNTO 0):="0000"; BEGIN -- REGISTRO DE ESTADO PROCESS(clk, inicio, next_state) BEJÍN IF inicio = '0' THEN state <= S10; -- todo apagado ELSIF clk'event AND clk = '1' THEN state <= next_state; END IF; END PROCES; -- LÓGICA COMBINACIONAL PARA DEFINIR EL IEC FRANCISCO JAVIER TORRES VALLE 81 CAPÍTULO IV: DESCRIPCIÓN DE CIRCUITOS DIGITALES -- SIGUIENTE ESTADO PROCESS(clk, state, sensor) BEGIN CASE state IS WHEN S0 => IF sensor='0' THEN next_state <= S0; ELSIF sensor='1' THEN next_state <= S1; END IF; WHEN S1 => next_state <= S2; WHEN S2 => next_state <= S3; WHEN S3 => next_state <= S4; WHEN S4 => next_state <= S5; WHEN S5 => next_state <= S6; WHEN S6 => next_state <= S7; WHEN S7 => next_state <= S8; WHEN S8 => next_state <= S9; WHEN S9 => next_state <= S10; WHEN S10 => IF inicio = '0' THEN next_state <= S10; ELSE next_state <= S0; END IF; WHEN OTHERS => NULL; END CASE; END IF; END PROCESS; -- LÓGICA COMBINACIONAL DE SALIDA outputs <= all_off WHEN (state=S10) ELSE vaf_on WHEN (state=S0 AND sensor='0') ELSE vac_on WHEN (state=S1) ELSE vac_on WHEN (state=S2) ELSE mot_on WHEN (state=S3) ELSE mot_on WHEN (state=S4) ELSE mot_on WHEN (state=S5) ELSE mot_on WHEN (state=S6) ELSE des_on WHEN (state=S7) ELSE des_on WHEN (state=S8) ELSE des_on WHEN (state=S9) ELSE all_off; END state_machine; IEC FRANCISCO JAVIER TORRES VALLE 82 CAPÍTULO V: IMPLEMENTACIÓN FILTROS DIGITALES EN FPGA's V IMPLEMENTACIÓN DE FILTROS DIGITALES EN FPGA'S IEC FRANCISCO JAVIER TORRES VALLE 83 CAPÍTULO V: IMPLEMENTACIÓN FILTROS DIGITALES EN FPGA's 5.1 INTRODUCCIÓN Un FPGA es un dispositivo cuyas características pueden ser modificadas, manipuladas o almacenadas mediante programación. La arquitectura de un FPGA (Field Programmable Gate Array) consiste en arreglos de múltiples celdas lógicas las cuales se comunican unas con otras mediante canales de conexión verticales y horizontales. Cada celda lógica contiene arreglos de compuertas lógicas AND y OR, así como un número definido de registros y multiplexores. Mediante estos recursos es posible implementar funciones matemáticas y de almacenamiento de datos. Dada la gran densidad de compuertas con las que cuenta un FPGA, es posible implementar sistemas digitales muy complejos, entre los que destaca el filtrado digital. Además, en un FPGA es posible realizar modificaciones de último minuto sin que esto implique grandes alteraciones en el hardware o en el software. 5.2 ANTECEDENTES En las últimas tres décadas la ingeniería se ha visto revolucionada en el campo del procesamiento digital de señales, donde los filtros digitales forman un apartado muy importante, ya que estos se encuentran en una extensa gama de aplicaciones. Desde procesamiento de audio y vídeo hasta control de motores; donde la utilización del filtrado digital incluye ventajas como: 5.3 MARCO TEÓRICO El término filtro se utiliza comúnmente para describir un dispositivo que discrimina aquello que pasa a través de él. Así, por ejemplo, un filtro de aire permite que sólo pase aire a través de éste, evitando que las partículas de polvo presentes en el aire lo atraviesen. Un filtro digital es un sistema lineal e invariante en el tiempo (LTI) que modifica el espectro en frecuencia de la señal de entrada X(w), según la respuesta que tenga en frecuencia H(w) (conocida como función de transferencia), para dar lugar a una señal de salida con espectro: Y(w) = H(w) * X(w). En cierto sentido, H(w) actúa como una función de ponderación o función de conformación espectral para las diferentes componentes frecuenciales de la señal de entrada. Los sistemas LTI se clasifican como: FIR (finite impulse response) que se caracterizan pos ser sistemas no recursivos, e IIR (infinite impulse response) que se distinguen por tener retroalimentación en la señal salida. 5.3.1 FILTROS FIR Un filtro FIR de orden M se describe mediante la ecuación en diferencias: y(n) = b0 x(n) + b1 x(n1) + b2 x(n-2) + bM x(n-M), donde la secuencia bk son los coeficientes del filtro. En este tipo de filtrado no existe retroalimentación. Además, la respuesta al impulso H(w), es de duración finita ya que si la entrada se mantiene en cero durante M periodos consecutivos la salida también será cero. Algunas de las ventajas de este tipo de filtros son las siguientes: 1) El ancho de banda y la calidad del filtro no están necesariamente relacionadas. 2) Al utilizar dispositivos programables, la función de transferencia de el filtro puede ser transformada sin más modificaciones que el cambio de los coeficientes en memoria. 1) Un filtro FIR puede ser diseñado para tener fase lineal. 3) Variables como temperatura o alteraciones en el voltaje no afectan la funcionalidad del circuito. 4) El costo de la aplicación es relativamente bajo. 3) Los errores por desbordamiento no son problemáticos porque la suma de productos en un filtro FIR es desempeñada por un conjunto finito de datos. 2) Siempre son estables porque son hechos únicamente con ceros en el plano complejo. 4) Un filtro FIR es fácil de comprender e implementar. IEC FRANCISCO JAVIER TORRES VALLE 84 CAPÍTULO V: IMPLEMENTACIÓN FILTROS DIGITALES EN FPGA's Figura 5.1 Estructura para la realización de filtros IIR 5.3.2 FILTROS IIR Los filtros IIR corresponden directamente al equivalente analógico. Una forma de diseñar filtros IIR es creando la función de transferencia deseada en el dominio analógico para transformarla al dominio z y después calcular los coeficientes del filtro IIR mediante los cuales se obtiene la siguiente ecuación en diferencias: y(n) = b0 x(n) + b1 x(n – 1) + b2 x(n – 2) + ... bM x(n –M) - a1 y(n – 1) - a2 y(n – 2) - ....- aN y(n – N), donde las variables ak y bk son los coeficientes del filtro. Dentro de las ventajas que ofrecen los filtros IIR sobre los tipo FIR encontramos: 1) Los filtros IIR requieren menos memoria y menos instrucciones para implementar su función de transferencia. 2) Un filtro IIR se diseña mediante el calculo de polos y ceros en el plano complejo. El uso de polos confieren a un filtro IIR la capacidad de implementar funciones de transferencia que es imposible realizar mediante filtros FIR. Sin embargo, algunas consideraciones que se deben considerar en la implementación de filtros IIR son las siguientes: 1) Los filtros IIR no son necesariamente estables, es tarea del diseñador buscar la estabilidad del sistema. 2) Los filtros IIR producen en general distorsión de fase. 3) La posibilidad desbordamiento de resultados en la operaciones realizadas deben ser consideradas ya que un filtro IIR se implementa mediante sumas de productos que están basadas en una suma infinita. La implementación de filtros IIR puede hacerse de varias formas. Asumiendo el comportamiento lineal e invariante en el tiempo del sistema, la ecuación en diferencias de un filtro puede ser manipulada matemáticamente para obtener una realización con N elementos de memoria, (N + M + 1) multiplicadores y N sumadores, conocida como Forma Directa II Transpuesta. 3) Es posible trasladar un filtro IIR a un modelo analítico. IEC FRANCISCO JAVIER TORRES VALLE 85 CAPÍTULO V: IMPLEMENTACIÓN FILTROS DIGITALES EN FPGA's Figura 5.2 Implementación de filtros IIR mediante FDII-T 1) Establecer las especificaciones del filtro, como lo son: ancho de banda, atenuaciones, ganancias, etc. (retraso de una unidad), z -2 (dos unidades), etc. Por lo que los filtros digitales pueden realizarse usando los elementos correspondientes a las operaciones de multiplicación, adición y almacenaje de datos en el FPGA, utilizando alguna de las estructuras para la realización de sistemas LTI. Una correcta elección de la estructura a implementar puede optimizar significativamente la eficacia del sistema. 2) Determinar la función de transferencia que cumpla las especificaciones. 5.6 5.4 METODOLOGÍA DE DISEÑO PARA FILTROS DIGITALES El proceso de diseño de un filtro digital requiere de los siguientes pasos. 3) Elaborar un diagrama a bloques con las operaciones a realizar, el cual especifica en hardware los elementos del circuito y sus interconexiones. 5.5 IMPLEMENTACIÓN EN FPGA'S El almacenaje de un dato significa retrasar su uso una cantidad normalmente igual al periodo de muestreo. Este retraso se representa mediante z -1 IEC FRANCISCO JAVIER TORRES VALLE DISEÑO DE UN FILTRO PASA-BAJAS Un filtro pasa - bajas ideal es aquel que permite pasar todas aquellas frecuencias que se encuentran por debajo de una frecuencia de corte especificada (fc), atenuando las que se encuentran por encima de esta. La siguiente ecuación en diferencias corresponde a un filtro IIR pasa - bajas tipo butteworth de orden 5, frecuencia de muestreo de 48.8 kHz y con una frecuencia de corte a 5 kHz: 86 CAPÍTULO V: IMPLEMENTACIÓN FILTROS DIGITALES EN FPGA's y(n) = 0.0014*x(n) + 0.0071*x(n-1) + 0.0142*x(n-2) + 0.0142*x(n-3) + 0.0071*x(n-4) + 0.0014*x(n-5) + 2.9272*y(n-1) - 3.7016*y(n-2) + 2.4521*y(n-3) - 0.8422*y(n-4) + 0.1191*y(n-5) A continuación se muestra la respuesta en frecuencia del sistema en magnitud y fase. F U N C I Ó N D E T R A N SF E R E N C I A 1 .2 1 |H(F)| 0 .8 0 .6 0 .4 0 .2 0 10 1 10 2 10 3 10 4 10 5 10 3 10 4 10 5 F 3 2 <) H(F) 1 0 -1 -2 -3 10 1 10 2 F Figura 5.3 Respuesta del filtro en magnitud y fase La gráfica anterior sería la función de transferencia ideal del filtro a implementar, pero en un sistema digital todo se trabaja en el sistema binario por lo que debemos convertir los coeficientes obtenidos a dicho sistema. Dicha conversión implica una cantidad considerable de bits si es que se desea obtener la misma calidad. Pero el utilizar más bits implica la utilización de mayor cantidad de recursos del FPGA, el cual en el presente trabajo es un XC4010XLPC84. De hecho un multiplicador de 20 bits requiere del 65% de los recursos de este dispositivo, por lo que se opto por implementar el filtro utilizando la función de transferencia H(ω) del filtro anterior con las primeras once muestras de la respuesta al impulso del sistema LTI y realizar el diseño del filtro utilizando la estructura FIR. Los coeficientes utilizados son los siguientes: b(n) = ( 1, 2, 3, 4, 4, 3, 2, 1, -1, -1, -1 ), los cuales cuando se digitalizan utilizando el formato complemento a dos quedan de la siguiente manera: bk = ( 0001, . IEC FRANCISCO JAVIER TORRES VALLE 0010, 0011, 0100, 0100, 0011, 0010, 0001, 1111, 1111, 1111 ) El diseño de la estructura FIR se realizo con VHDL para lo cual se describieron utilizando once registros en una configuración FIFO para realizar los retardos z-1 y cuyas salidas se multiplican por el coeficiente respectivo. EL dispositivo convertidor analógico - digital utilizado es el AK4520A el cual tiene una longitud de palabra de 20 bits con salida en complemento a dos. Por lo que el filtrado se realizo con once multiplicaciones de 20x4 y un acumulador de dichas operaciones. La cuantización de los coeficientes afecta la respuesta en frecuencia del sistema, a continuación se muestra la respuesta en frecuencia en magnitud del filtro con lo coeficientes cuantizados 87 CAPÍTULO V: IMPLEMENTACIÓN FILTROS DIGITALES EN FPGA's FU N C IÓ N D E T R A N SFE R E N C IA 20 18 16 14 |H(F)| 12 10 8 6 4 2 0 10 1 10 2 10 3 10 4 F Figura 5.4 Respuesta del filtro en magnitud utilizando los coeficientes cuantizados A continuación se muestra la descripción en VHDL de la estructura FIR. -------------------------------------- FIR ------------------------------------library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; package fir_coef is subtype coef_word is signed (3 downto 0); subtype coef_range is integer range 0 to 10; type coef_table is array (0 to 10) of coef_word; constant coef_rom: coef_table:= ( ("0001"), ("0010"), ("0011"), ("0100"), ("0100"), ("0011"), ("0010"), ("0001"), ("1111"), ("1111"), ("1111")); end fir_coef; library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.fir_coef.all; IEC FRANCISCO JAVIER TORRES VALLE entity fir is port(clk,reset,load: in std_logic; data_in: in signed (19 downto 0); data_out: out signed (19 downto 0)); end fir; architecture a_fir of fir is type fifo_array is array (0 to 10) of signed (19 downto 0); signal fifo: fifo_array; begin process (reset,clk,fifo,data_in) begin if reset = '0' then for i in 0 to 10 loop fifo(i) <= (others => '0'); end loop; elsif clk'event and clk = '1' then if load = '1' then for i in 1 to 10 loop fifo(i) <= fifo(i-1); end loop; fifo(0) <= data_in; end if; end if; end process; process (fifo) 88 CAPÍTULO V: IMPLEMENTACIÓN FILTROS DIGITALES EN FPGA's variable prod,data_tmp: signed (23 downto 0); begin data_tmp := (others => '0'); for i in 0 to 10 loop prod := fifo(i) * coef_rom(i); data_tmp := data_tmp + prod; end loop; data_out <= data_tmp(23)&data_tmp(18 downto 0); end process; end a_fir; El diseño del circuito se basa en el siguiente diagrama. IEC FRANCISCO JAVIER TORRES VALLE 89 CAPÍTULO V: IMPLEMENTACIÓN FILTROS DIGITALES EN FPGA's Figura 5.5 Filtro FIR implementado en el FPGA IEC FRANCISCO JAVIER TORRES VALLE 90 CAPÍTULO V: IMPLEMENTACIÓN FILTROS DIGITALES EN FPGA's A continuación se muestra las salidas obtenidas de la implementación del diseño, como señales de prueba se utilizaron senoidales de 1 Vpp aprox. a diferentes frecuencias. A la frecuencia de corte del filtro se debe obtener aprox. 0.5 Vpp lo cual es necesario para poder decidir si el filtro está bien diseñado. Figura 5.6 Salida del filtro a 1.027 kHz Figura 5.6 Salida del filtro a 2.024 kHz IEC FRANCISCO JAVIER TORRES VALLE 91 CAPÍTULO V: IMPLEMENTACIÓN FILTROS DIGITALES EN FPGA's Figura 5.6 Salida del filtro a 3.021 kHz Figura 5.6 Salida del filtro a 5 kHz IEC FRANCISCO JAVIER TORRES VALLE 92 CAPÍTULO V: IMPLEMENTACIÓN FILTROS DIGITALES EN FPGA's Figura 5.6 Salida del filtro a 6.061 kHz Figura 5.6 Salida del filtro a 7.092 kHz 5.7 hardware de un filtro digital puede implementar una gran variedad de filtros, sin que esto implique modificaciones en el circuito. RESULTADOS • Los filtros digitales cuentan con muchas ventajas que los hacen más atractivos que sus predecesores analógicos. • Al utilizar dispositivos programables, como un FPGA, la función de transferencia del filtro puede ser transformada sin más modificaciones que la reprogramación del dispositivo. Por lo que un simple diseño en IEC FRANCISCO JAVIER TORRES VALLE • Las funciones de transferencia de los filtros digitales cuentan con rigurosas especificaciones, como que las frecuencias que se desea sean rechazadas pueden ser extremadamente atenuadas sin sacrificar el ancho de banda que se está filtrando. 93 CAPÍTULO V: IMPLEMENTACIÓN FILTROS DIGITALES EN FPGA's V o (d b ) 5 0 1 .0 0 E + 0 0 1 .0 0 E + 0 1 1 .0 0 E + 0 2 1 .0 0 E + 0 3 1 .0 0 E + 0 4 -5 -1 0 db -1 5 -2 0 -2 5 -3 0 -3 5 -4 0 -4 5 F r e c u e n c ia (H z ) Frecuencia Vo (Volts) Vo (Hertz) (db) 1.00E-00 1 0 1.03E+03 1.044 0.374009 2.02E+03 0.981 -0.166619 3.02E+03 0.818 -1.744933 5.00E+03 0.475 -6.466127 6.06E+03 0.281 -11.02587 7.09E+03 0.168 -15.49381 1.00E+04 0.01 -40 Figura 5.7 Respuesta en frecuencia del filtro IEC FRANCISCO JAVIER TORRES VALLE 94 CONCLUSIONES CONCLUSIONES IEC FRANCISCO JAVIER TORRES VALLE 95 CONCLUSIONES CONCLUSIONES • • • Es posible verificar el funcionamiento del sistema dentro del proceso de diseño sin necesidad de implementar el circuito. La cual se apoya en el hecho de que cualquier función lógica se puede realizar mediante una suma de productos. Las simulaciones del diseño, antes de que éste sea implementado mediante compuertas, permiten probar la arquitectura del sistema para tomar decisiones en cuanto a cambios en el diseño. • Las herramientas de síntesis tienen la capacidad de convertir una descripción hecha VHDL a compuertas lógicas y, además, optimizar dicha descripción de acuerdo a la tecnología utilizada. • Esta metodología elimina el antiguo método tedioso de diseño mediante compuertas, reduce el tiempo de diseño y la cantidad de errores producidos por el armado del circuito. • Las herramientas de síntesis pueden transformar automáticamente un circuito obtenido mediante la síntesis de un código en VHDL, a un circuito pequeño y rápido. Además, es posible aplicar ciertas características al circuito dentro de la descripción para afinar detalles (retardos, simplificación de compuertas, etc.) en la arquitectura del circuito y que estas características se obtengan en la síntesis de la descripción. • Las descripciones en VHDL proporcionan documentación de la funcionalidad de un diseño independientemente de la tecnología utilizada. • Un circuito hecho mediante una descripción en VHDL puede ser utilizado en cualquier tipo de dispositivo programable capaz de soportar la densidad del diseño. Es decir, no es necesario adecuar el circuito a cada dispositivo porque las herramientas de síntesis se encargan de ello. • Una descripción realizada en VHDL es más fácil de leer y comprender que los netlist o circuitos esquemáticos. • La fabricación de dispositivos de lógica programable se basa en los siguientes dos conceptos. IEC FRANCISCO JAVIER TORRES VALLE FUNCIONALIDAD COMPLETA • CELDAS DE FUNCIONES UNIVERSALES. También denominadas generadores de funciones, son bloques lógicos configurados para procesar cualquier función lógica, similares en su funcionamiento a una memoria. En estas celdas se almacenan los datos de salida del circuito combinacional en vez de implementar físicamente la ecuación booleana. • En la descripción de circuitos con VHDL el dispositivo utilizado es de vital importancia, ya que de este depende el proceso de síntesis mediante el cual se obtiene la funcionalidad lógica implementada en el mismo. • Lo que ha hecho que VHDL sea en un tiempo tan corto el lenguaje de descripción de hardware más utilizado por la industria electrónica, es su independencia con la metodología utilizada por cada diseñador, su capacidad de descripción a diferentes niveles de abstracción, y en definitiva la posibilidad de poder reutilizar en diferentes aplicaciones un mismo código. • La clave para describir y sintetizar fácilmente circuitos digitales con VHDL es pensar en términos de compuertas y registros y no en función de variables y subrutinas. • WARP y Foundation son herramientas de síntesis que utilizan VHDL como su lenguaje de descripción de circuitos, cada uno con sus propias restricciones del lenguaje. Por lo que es necesario consultar el manual de referencia de cada herramienta para conocer dichas restricciones. • Al utilizar dispositivos programables, como un FPGA, la función de transferencia de un filtro puede ser transformada sin más modificaciones que la reprogramación del dispositivo. Por lo que un simple diseño en hardware de un filtro digital puede implementar una gran variedad de filtros, sin que esto implique modificaciones en el circuito. 96 BIBLIOGRAFÍA BIBLIOGRAFÍA IEC FRANCISCO JAVIER TORRES VALLE 97 BIBLIOGRAFÍA VHDL FOR PROGRAMMABLE LOGIC THE PROGRAMMABLE LOGIC DATA BOOK KEVIN SKAHILL XILINX, INC. CYPRESS SEMICONDUCTOR & 1999 ADDISON WESLEY 1996 CYPRESS PROGRAMMABLE LOGIC DATA BOOK VHDL DOUGLAS L. PERRY CYPRESS SEMICONDUCTOR 1997 MCGRAW HILL 2ª EDICIÓN DIGITAL SIGNAL PROCCESING JOHN G. PROAKIS, VHDL, LENGUAJE PARA SÍNTESIS Y DIMITRIS G. MANOLAKIS MODELADO DE CIRCUITOS PRENTICE HALL FERNANDO PARDO, JOSÉ A. BOLUDA 1992 EDITORIAL RA-MA 1999 DISCRETE-TIME SIGNAL PROCCESING A. V. OPPENHEIM VHDL REFERENCE GUIDE R. W. SCHAFFER XILINX, INC. PRENTICE HALL 1999 1989 ACTEL HDL CODING, STYLE GUIDE VHDL LENGUAJE PARA SÍNTESIS Y ACTEL CORPORATION MODELADO DE CIRCUITOS 1999 http://bugs.uv.es/dpt/atc/asignat uras/ti/curso/curso.html WARP, LANGUAGE REFERENCE MANUAL CYPRESS SEMICONDUCTOR 1998 MAX+PLUS II, GETTING STARTED MANUAL ALTERA CORPORATION 1999 VHDL LENGUAJE PARA SÍNTESIS Y MODELADO DE CIRCUITOS (2) http://tapec.uv.es/VHDL/libro.ht ml IZQUIERDA DE LENGUAJES DE DESCRIPCIÓN DE HARDWARE VHDL http://cseg.inaoep.mx/~ariasm/arqcomp/v hdlweb/indexiz.htm IEC FRANCISCO JAVIER TORRES VALLE 98 BIBLIOGRAFÍA LÓGICA PROGRAMABLE DE ALTA DENSIDAD HUMBERTO DE JESÚS OCHOA DOMÍNGUEZ http://intranet.uacj.mx/ SYNTHESIS USING VHDL http://www.cedcc.psu.edu/ee497f/rassp_6 0/index.htm RASSP TECHNOLOGY BASE VHDL MODELING DEVELOPMENT http://www.erc.msstate.edu/mpl/ rassp/modeling/html/modeling.ht ml THE HAMBURG VHDL ARCHIVE http://tech-www.informatik.unihamburg.de/vhdl/vhdl.html VHDL EXAMPLES FOR SYNTHESIS http://eecad.sogang.ac.kr/~chang/vhdl/We lcome.html EXAMPLES FOR VHDL VHDL AND VERILOG REFERENCES AND TUTORIALS http://www.optimagic.com/tutori als.html http://www.eej.ulst.ac.uk/exa/exam.html NORTHEASTERN UNIVERSITY VHDL DESIGN & DEVELOPMENT http://www.ece.neu.edu/info/vhd l/vhdl.html VHDL COOKBOOK (C) 1990, PETER J. ASHENDEN http://www.fastsys.co.kr/~jwpar k/Outside/Comp/EDA/Cookboo k.html VHDL INTERNATIONAL HOME PAGE AN INTRODUCTION TO VHDL http://www.vhdl.org/ http://www.acceda.com/h_intro.htm VHDL RESOURCE PAGE DOULOS VHDL TRAINING VERILOG TRAINING DOULOS HOME PAGE http://www.doulos.co.uk/thewin ningedge/index.htm http://www.ece.uc.edu/~rmiller/ VHDL/intro.html VHDL-ONLINE MAIN FRAME http://www.vhdl-online.de/ RASSP HOME PAGE http://rassp.scra.org/ ACTEL CORPORATION'S HOME PAGE http://www.actel.com/ ACTEL DESKTOP HOME http://www.acteldesktop.com/ IEC FRANCISCO JAVIER TORRES VALLE 99 BIBLIOGRAFÍA CYPRESS SEMICONDUCTOR CORPORATION http://www.cypress.com/ ALTERA WEB SITE http://www.altera.com/ XILINX HOME PAGE http://www.xilinx.com/ INTECTRA INC. http://www.intectra.com/ VHDL, LEGUAJE PARA LA SÍNTESIS Y DESCRIPCIÓN DE HARDWARE http://www.gdl.uag.mx/214/inicio.htm IEC FRANCISCO JAVIER TORRES VALLE 100