DISEÑO EN VHDL PARA FPGAs Raúl Mateos Gil. Ignacio Fernández Lorenzo. Pedro Martín Sánchez. Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín ÍNDICE 1. FLUJO DE DISEÑO VHDL SOBRE FPGAs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1. INTRODUCCIÓN. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2. STANDARD VITAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3. CREACIÓN DEL MODELO. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.4. SÍNTESIS DEL MODELO. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.5. IMPLEMENTACIÓN DEL MODELO. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1 1 2 3 4 2. DESCRIPCIÓN DEL DISEÑO A REALIZAR. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 2.1. CREACIÓN DEL MÓDULO LOGIBLOX. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.2. MÓDULO BCD2SEG. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 2.3. MÓDULO CRONO.VHD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 2.3.1. Declaración de librerías. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 2.3.2. Definición de la entidad. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 2.3.3. Parte declarativa de la arquitectura. . . . . . . . . . . . . . . . . . . . . . . . . . . 14 2.3.4. Instantación de componentes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 2.3.5. Contador de décadas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 2.3.6. Registros de lapso. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 2.3.7. Máquina de estados. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 2.4. BANCO DE PRUEBAS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 2.5. FICHERO CONFBEHAVIORAL.VHD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 3. SIMULACIÓN FUNCIONAL DEL DISEÑO. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1. INTRODUCCIÓN. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1.1. Librerías. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2. MANEJO DEL SIMULADOR. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.1. Creación del proyecto. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.2. Creación de nuevas librerías y mapeado de las librerías a reutilizar . 3.2.3. Compilación del código fuente. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.4. Carga de la unidad de diseño a simular . . . . . . . . . . . . . . . . . . . . . . . 3.2.5. Selección de puntos de prueba. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.6. Avance y detención de la simulación. . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.7. Introducción de estímulos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.8. Análisis de resultados. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.9. Finalizar una sesión de simulación. . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3. PUNTOS DE RUPTURA. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.4. METODOLOGÍA DE TRABAJO. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 20 21 23 24 24 25 26 27 31 33 35 36 36 38 4. SÍNTESIS DEL DISEÑO. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1. OPERACIÓN INTERNA DEL SINTETIZADOR. . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.1. Generadores de módulos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2. MANEJO DEL SINTETIZADOR. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2.1. Inicialización del sintetizador. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2.2. Selección de la tecnología destino. . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2.3. Selección del método de codificación de las máquinas de estados. . . 4.2.4. Lectura de ficheros del diseño. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2.5. Selección del diseño actual. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2.6. Configuración de opciones de optimización. . . . . . . . . . . . . . . . . . . . 4.2.7. Optimización del diseño. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2.8. Almacenamiento del diseño. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 39 42 43 45 45 45 47 47 48 51 52 -i- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. 4.2.9. Exportación de la lista de conexiones. . . . . . . . . . . . . . . . . . . . . . . . . . 52 4.2.10. Uso de ficheros de scripts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 4.3. ANÁLISIS DE RESULTADOS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 5. IMPLEMENTACIÓN DEL DISEÑO. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 5.1. USO DE FICHEROS DE RESTRICCIONES. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 6. SIMULACIÓN A NIVEL DE PUERTAS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 -ii- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín 1. FLUJO DE DISEÑO VHDL SOBRE FPGAs. 1.1. INTRODUCCIÓN. La figura 1.1 muestra el diagrama de flujo para el diseño en VHDL de sistemas implementados sobre FPGAs de Xilinx. El proceso de diseño se divide en tres fases: creación del modelo, síntesis e implementación. Al finalizar cada una de las fases es preciso comprobar la validez del diseño mediante simulación, utilizandose distintos tipos de simulación en cada una de ellas: ! Simulación funcional RTL para validar el modelo VHDL creado. ! Simulación funcional post-síntesis a nivel de puertas para validar el modelo sintetizado. ! Simulación temporal post-implementación para validar la implementación del modelo implementado. El diseño contiene componentes LogiBLOX instanciados Editor VHDL Plantillas de instantación Modelo de simulación del componente LogiBLOX. VHDL VHI SIMULADOR VHDL Simulación RTL. Restricciones de diseño. Fichero de lista de conexiones de salida. SINTETIZADOR VHDL XNF EDIF LIsta de conexiones en formato nativo. UNISIM VITAL .NGC VHDL Simulación post-sintesis pre-implementación. LogiBLOX SIMULACIÓN FUNCIONAL. Fichero fuente RTL VHDL LogiBLOX Fichero de restricciones de usuario. Banco de pruebas VHDL HERRAMIENTAS DE IMPLEMENTACIÓN Ficheros de informes BIT JEDEC Fichero de programación del dispositivo. EDIF SDF VHDL Ficheros de lista de conexiones para simulación post-implementación SIMPRIM VITAL SIMULACIÓN TEMPORAL. Comportamiento Figura 1: Flujo de diseño en VHDL para FPGAs de Xilinx. El banco de pruebas creado para validar el modelo es único, siendo utilizado en todos los tipos de simulación mencionados. Las dos últimas son simulaciones a nivel de puertas, ya que el diseño esta expresado como una descripción estructural VHDL en términos de las celdas de la tecnología destino para la que se va implementar. 1.2. STANDARD VITAL Para poder realizar simulaciones temporales mediante un simulador VHDL se necesitan modelos VHDL con información temporal de los elementos de la librería de la tecnología destino. El standard VITAL (VHDL Initiative Towards ASIC Library) define las técnicas de generación de estos modelos de -1- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. simulación mediante dos paquetes denominados VITAL_Timing y VITAL_Primitives. En este caso el fabricante del ASIC debe proporcionar las librerías VITAL en la que estén descritas las celdas básicas de la tecnología destino. La retroanotación de los retardos internos (tanto debidos a elementos activos como a interconexiones) se realiza mediante ficheros SDF. Se pueden utilizar distintos ficheros SDF a lo largo de las distintas etapas del proceso de diseño. Alguno de estos ficheros pueden contener datos temporales pre-layout. Otros pueden contener restricciones de caminos críticos de señales o información temporal post-layout. Xilinx proporciona varias librerías VITAL para realizar simulaciones VHDL de diseños para FPGAs. La librería UNISIM es una librería VITAL en la que se han desactivado las comprobaciones de violaciones de temporización para realizar simulaciones funcionales con retardos unitarios. Al sintetizar una descripción VHDL RTL para FPGAs de Xilinx las celdas de la tecnología destino que aparecen en el fichero de salida corresponden a las celdas primitivas definidas en la biblioteca unificada de Xilinx de las herramientas de captura de esquemas. La librería UNISIM contiene los modelos VITAL de estas celdas básicas. Además se incluyen los modelos de otras celdas primitivas que se pueden instanciar como componentes para aprovechar los recursos de la FPGA (por ejemplo, el oscilador integrado OSC4 de la familia Spartan XL). Sin embargo UNISIM no dispone de modelos para los componentes de tipo macro que aparecían en la librería unificada de las herramientas de captura de esquemas. Esto impide realizar simulaciones RTL de diseños en los que se instancien estas macros como componentes descritos por una lista de conexiones. La librería XILINXCORELIB se utiliza para realizar simulaciones funcionales de diseños en los que aparezcan componentes creado con la herramienta COREGEN. Finalmente la librería SIMPRIMS es una librería VITAL para realizar simulaciones temporales a nivel de puertas. En esta librería se almacenan los modelos de los componentes físicos que aparecen en el interior de una FPGA (LUTs, biestables, etc). En este caso las comprobaciones de violaciones de temporización si están activadas. La retroanotación de los retardos de los elementos activos (LUTs, biestables, buffers triestado, etc) y de las interconexiones se realizan mediante un fichero SDF.A continuación se describirán en detalle cada una de las fases del flujo de diseño así como las peculiaridades de la simulación utilizada para la verificación de los resultados obtenidos. 1.3. CREACIÓN DEL MODELO. El primer paso consiste en crear un modelo RTL del diseño que se pretende realizar. Para ello se puede utilizar un editor de texto. El diseño puede contener: ! Código VHDL genérico que describe lógica independiente de la tecnología donde se va a implementar. ! Componentes instanciados propios de la arquitectura del dispositivo en el que se va a implementar. Un ejemplo de esto sería el uso del oscilador interno OSC4 de la familia Spartan XL. ! Componentes instanciados creados mediante COREGEN. Un ejemplo de esto sería el uso de una memoria, un contador, etc creados mediante COREGEN. Para el caso de utilización de componentes propios de la arquitectura del dispositivo el sintetizador obtiene la descripción de dichos componentes de la biblioteca de celdas de la tecnología destino. El formato de esta biblioteca dependerá de la herramienta de síntesis utilizada. En algunos casos dicha biblioteca está integrada en la propia herramienta como una biblioteca más del sistema. Tal es el caso del sintetizador “Leonardo Spectrum”. En otros casos la biblioteca aparece como conjunto -2- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín de macros expresadas como listas de conexiones en formato XNF. Estos componentes aparecen como módulos sin definición (cajas negras) en la descripción VHDL donde se instancian. Si el diseño utiliza componentes COREGEN es preciso crearlos previamente mediante esta herramienta. Al crear un componente COREGEN, se genera un fichero VHDL con una definición abstracta del funcionamiento del mismo, que puede ser simulado y sintetizado. También se crea un archivo de lista de conexiones para la implementación (.EDN). Será posteriormente durante la implementación del diseño cuando las herramientas de implementación de Xilinx enlacen esta lista de conexiones con la del diseño principal obtenida tras el proceso de síntesis. Si bien el componente obtenido es un módulo sin definición aparente, COREGEN puede crear un fichero VHDL de comportamiento para permitir la verificación del diseño completo mediante simulación. Este fichero tiene extensión .VHD. También puede generar un fichero de declaración del componente en VHDL con extensión VHO. Este fichero contiene una plantilla con las construcciones necesarias para la declaración e instanciación del componente COREGEN en el fichero VHDL donde se vaya a utilizar, lo que facilita el desarrollo de diseños con este tipo de componentes. Antes de proceder a la síntesis del diseño es preciso verificar el modelo creado mediante simulación. Se trata de una simulación funcional en la que el diseño está descrito con construcciones RTL de alto nivel. Si el diseño utiliza componentes propios de la tecnología destino es preciso utilizar la librería de simulación XILINXCORELIB. Estos componentes COREGEN no son sintetizables por lo que su declaración se intercala entre directivas de inhabilitación/ habilitación del proceso de síntesis. Estas directivas aparecen como “comentarios sintéticos” en el fichero fuente. La sintaxis de tales directivas debe ser aceptada por la herramienta de síntesis en cuestión. Estas directivas son -- synopsys translate_off ......... -- synopsys translate_on las cuales son aceptadas por Leonardo Spectrun. 1.4. SÍNTESIS DEL MODELO. Una vez validado el modelo creado se procede a la síntesis de éste. El resultado de la síntesis es una lista de conexiones en formato EDIF o XNF. Si en el proceso de síntesis se fijan restricciones de diseño (topológicas o temporales) que afectan al proceso de implementación éstas se exportan en la propia lista de conexiones. Para comprobar los resultados de la síntesis es preciso realizar una simulación funcional (retardos unitarios) a nivel de puertas (expresadas como componentes de UNISIM). Para ello se debe disponer de una herramienta capaz de generar una descripción estructural VHDL equivalente a las listas de conexiones mencionadas. El procedimiento a seguir es similar a la simulación funcional RTL. Los modelos de los componentes COREGEN siguen siendo modelos de comportamiento. Si la herramienta de síntesis no es capaz de proporcionar este fichero VHDL habrá que utilizar las herramientas de implementación para poder realizar este tipo de simulación. -3- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. 1.5. IMPLEMENTACIÓN DEL MODELO. Una vez sintetizado el diseño se procede a su implementar. La figura 1.2 muestra el diagrama de flujo de las herramientas de implementación de Xilinx. En ella aparecen las distintas fases en que se divide la implementación del diseño y las herramientas utilizadas en cada una de éstas. FASES HERRAMIENTAS Lista de conexiones de entrada .XNF o EDIF NGDBUILD Diseño jerárquico aplanado .NGD MAP Traducción lógica a física. Agrupamiento de LUTs y FFs en CLBs .NCD .PCF TRCE Estimación de retardos estáticos. PAR Emplazamiento del diseño físico Interconexión del diseño físico. .NCD TRCE Estimación de retardos estáticos. NGDANNO & NGD2VHDL Retroanotación de retardos. Generación de ficheros simulación temporal VHDL . BITGEN Obtención del fichero de configuración. VHDL SDF .BIT Figura 2: Flujo de implementación. El diseño a implementar puede estar descrito en base a un conjunto de ficheros de listas de conexiones XNF o EDIF formando una estructura jerárquica. En esta jerarquía pueden aparecer componentes en uno de los ficheros cuya estructura interna está descrita en otro fichero. Tal es el caso de aquellos diseños que contienen componentes COREGEN en los que cada uno de ellos está descrito por una lista de conexiones EDN. En la fase de traducción (traslate), realizada mediante la herramienta NGDBUILD, se enlazan los ficheros de lista de conexiones creando un único fichero de salida en el que queda reflejada la jerarquía citada. El formato de este fichero de salida se denomina -4- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín NGD (Native Generic Design) y contiene componentes lógicos: puertas lógicas, biestables, RAMs, etc. Esta herramienta puede generar también un fichero VHDL que contiene una descripción estructural del diseño en base a componentes contenidos en la librería UNISIM. El cual se puede utilizar para realizar simulaciones funcionales post-síntesis cuando el sintetizador no es capaz de generar este tipo de ficheros VHDL. En este caso, los componentes generados mediante COREGEN están descritos también mediante elementos de la librería UNISIM, por lo que no se ha de emplear los ficheros VHDL de comportamiento de estos componentes ni la librería XILINXCORELIB. En la fase de mapeado (map) se mapean mediante la herramienta MAP los componentes lógicos en los componentes físicos de que dispone la FPGA: tablas LUT, biestables, buffers triestado, etc. A continuación se encapsulan estos componentes físicos en bloques configurables (CLBs e IOBs), creando un fichero de salida en formato NCD (Native Circuit Design). En esta fase se realiza un análisis estático de tiempos mediante la herramienta TRCE. En él se analizan los caminos críticos de las señales comprobando el cumplimiento de las restricciones temporales introducidas mediante el fichero PCF (Project Constrains File). Esta evaluación es sólo preliminar ya que todavía no se dispone de la información de los retardos debidos a las interconexiones. Si el diseño cumple las restricciones temporales impuestas se pasa a realizar el emplazamiento e interconexión de los bloques configurables en la FPGA mediante la herramienta PAR. Esto corresponde a la fase denominada place & routing. La herramienta PAR genera un fichero de lista de conexiones en formato NCD. Una vez finalizado este proceso se dispone de toda la información de retardos internos (elementos activos e interconexiones). Con la herramienta TRCE se puede realizar de nuevo un análisis estático de tiempos esta vez con todos los datos de retardos internos. En la siguiente fase se obtienen la información para realizar simulaciones temporales del diseño completo. En primer lugar la herramienta NGDANNO retroanota la información de retardos internos. A continuación la herramienta NGD2VHDL crea un fichero VHDL estructural en base a los componentes físicos de la FPGA y un fichero SDF con los retardos internos de la FPGA. Los modelos de simulación de estos componentes se encuentran en la librería SIMPRIM. La retroanotación de retardos se realiza mediante un fichero SDF. Utilizando estos ficheros se puede realizar la verificación del diseño final mediante una simulación temporal VHDL post-síntesis post-implementación tal y como muestra la figura 1.1. Finalmente la herramienta BITGEN genera el fichero de configuración de la FPGA. 2. DESCRIPCIÓN DEL DISEÑO A REALIZAR. Para ilustrar el proceso de diseño en VHDL para FPGAs se empleará como ejemplo de diseño la realización de un cronometro digital con precisión de segundos y valor máximo de cuenta de un minuto. Con este diseño se pretende ilustrar las situaciones más frecuentes que aparecen en los diseños para FPGAs descritos en VHDL. El diseño se implementará en una FPGA XC2S50ETQ144-6 , utilizando para su desarrollo la placa empleada en el laboratorio. La figura 1.3 muestra el diseño a realizar. -5- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. OSCILADOR FPGA Vcc Vcc R RST clk R DisplayUnidades MARCHA lapso rst UPDOWN P1 DisplayDecenas Figura 3: Diseño a realizar La señal de reloj del sistema proviene de un osiclador externo, que proporciona una señal de frecuencia 10 MHz. El número de segundos transcurridos se visualizará sobre sendos displays de 7 segmentos conectados a la FPGA. El sistema dispone de un pulsador de reset para inicializar la cuenta del tiempo transcurrido. Además se dispone de otro pulsador para implementar la función de lapso. Al pulsar este pulsador se congela el tiempo actual de forma que sobre los displays se muestra dicho instante de tiempo mientras que el cronómetro sigue contando internamente. Al volver a pulsar el pulsador de lapso se muestra el tiempo transcurrido actualmente. Si bien en la figura anterior las resistencias conectadas a los pulsadores aparecen como componentes externos, en el diseño a realizar éstas se implementarán mediante las resistencias de pull-up de los IOBs correspondientes a estos terminales de la FPGA. La figura 1.4 muestra el diagrama de bloques del diseño a realizar. PRESCALER DIVISOR 1 / 10E10 CONTADOR 0-59 EN1HZ REGISTROS BCD2SEG EN prescaler.vhd BCD2SEG clk EN bcd2seg.vhd rst FSM lapso crono.vhd Figura 4: Diagrama de bloques del diseño. La descripción VHDL de este diseño está compuesta de varios ficheros. El fichero bcd2seg.vhd contiene la descripción de un decodificador BCD a 7 segmentos para displays de cátodo común. Este decodificador se instanciará como sendos componentes en la entidad de mayor jerarquía que se encuentra almacenada en el fichero crono.vhd. En esta entidad se intancia también el componente PRESCALER que proporciona la señal de 1 Hz, emplada para contar los segundos. Esta señal se -6- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín obtiene de dividir la frecuencia de la señal de reloj clk por un factor de 10E10. Este componente se generará mediante COREGEN. El tiempo transcurrido viene indicado mediante un contador de décadas de 2 dígitos (unidades y decenas). Para implementar la función de congelación del tiempo se intercalan sendos registros entre la salida del contador y los decodificadores BCD a 7 segmentos. Cuando la señal de habilitación de estos registros está activa la salida de los registros reflejan el valor actual de cuenta. Si por el contrario la señal de habilitación está desactivada no se actualiza la salida del contador sobre los displays implementando de esta forma la función de congelación. La señal de habilitación de estos registros se controla mediante una máquina de estados que recibe como entrada la señal procedente del pulsador de lapso, y cuyo grafo se muestra en la figura 1.5. La variable P indica el estado del pulsador: 1 sin pulsar, 0 pulsado. P=1 P=0 S1 1 P=0 P=1 S4 S2 1 0 P=1 S3 P=0 P=0 0 P=1 Figura 5: Grafo de la máquina de estados. Inicialmente la máquina parte del estado S1 (la salida está a 1), de forma que la cuenta no está congelada. Si en este estado se pulsa el pulsador (P=0) se pasa al estado S2, inhabilitandose el refresco de los registros (la salida pasa a 0). Se permanece en este estado mientras el pulsador se encuentre activado. Al liberarse (P=1) se pasa al estado S3 (la salida permanece a 0), donde se espera hasta que se vuelva a activar el pulsador (P=0) momento en el cual se pasa al estado S4 (la salida pasa a 1), habilitando de nuevo el refresco de los registros. El sistema permanece en S4 mientras el pulsador permanece activado, pasando a S1 al liberarse. Una vez descrito el comportamiento del diseño se pasará describir el código VHDL a utilizar para implementarlo. En el archivo codigo.zip se encuentran todos los ficheros VHDL necesarios para realizar la aplicación antes descrita. Estos archivos se almacenarán en el directorio raíz del diseño. En este grupo se incluyen todos los ficheros fuente VHDL empleados, tanto los desarrollados por el diseñador, como los generados automáticamente por las herramientas de síntesis (Leonardo), así como las de implementación (ISE 4.1): Éstos ultimo serán utilizados, ademas de configurar la FPGA, para realizar la simulación temporal del diseño. Otros ficheros son los pertenecientes a los componentes COREGEN utilizados. Por tanto, si el diseño contiene componentes COREGEN (como es el caso que nos ocupa), el directorio de proyecto de estos componentes deberá ser el directorio raíz. Finalmente también se almacenará en el directorio raíz el fichero de restricciones de usuario (.ucf) empleado para asociar las señales externas del diseño a terminales concretos de la FPGA. En el archivo herramientas.zip se encuentran archivos scrips a utilizar con las herramientas de simulación y síntesis que permitirán simplificar la fase de diseño. a lo largo de este manual se irán explicando la funcionalidad de cada uno de ellos. -7- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. 2.1. CREACIÓN DEL MÓDULO COREGEN. Como se ha comentado el módulo prescaler se va a crear mediante COREGEN. Esta herramienta permite generar nuevos componentes a partir de un modelo básico predefinido que el usuario parametriza y ajusta a sus necesidades. Esta herramienta se ejecuta seleccionando: Inicio º Programas º Xilinx ISE4.1 º Accesorios Esto arranca la herramienta COREGEN apareciendo la pantalla de Setup mostrada en la figura 1.7, que nos permite crear un proyecto nuevo o acceder a uno ya creado. Un proyecto se considera como el subdirectorio donde se almacenan los componentes creados por esta herramienta. Para nuestra aplicación será el mismo en el que se almacena el código VHDL. Figura 7: Selección de un proyecto para COREGEN. Sise ha optado por la opción de crear un proyecto nuevo (Create New Project) aparece la ventana mostrada en la figura 1.8, en la que se selecciona el formato del archivo de salida. En nuestro caso se debe seleccionar las opciones VHDL y la herramienta de síntesis utilizada (exemplar, para el caso de utilizar Leonardo Spectrum). Así mismo, también se selecciona la familia de FPGAs para la que se va a crear el componente. -8- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín Figura 8: Ventana de configuración de COREGEN. En la pestaña Project Directory debe aparecer el path del directorio donde se almacenará el componente creado con COREGEN. Según lo indicado, para este ejemplo debe ser c:\tutorial. Una vez creado un proyecto se pueden modificar las anteriores opciones utilizando la herramienta Project Options del menú Project. Una vez fijadas las distintas opciones se validan mediante el botón Aceptar mostrandose a continuación la ventana principal de COREGEN (figura 1.9) Figura 9: Ventana principal de COREGEN. En el campo Target Family se muestran el tipo de agrupación de los elementos que se poden crear, pudíendose cambiar la selección con la pestaña View Catalog. En el campo Contens Of se representan los componentes que podemos crear. Por su parte, en el campo Generated Modules se muestran todos los componentes que se encuentra en el proyecto de trabajo, haciendo doble clic sobre cada uno de ellos se pueden volver a editar y en consecuencia a modificar su funcionalidad. Una vez seleccionado un componente en la ventana Contens Of, seleccionando se accede a un archivo en formato PDF en el que se detalla la funcionalidad de cada uno de los terminales del -9- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. componente. El prescaler se va a crear a partir de un contador, para ello se selecciona la carpeta Counters en Basic Elements para entran en el modelado del componente se hace doble clic sobre el elemento de la ventana Contens Of o se ejecuta , apareciendo el menú de la figura 1.10 que permite parametrizar el componente de acuerdo con nuestras necesidades. En este caso debemos diseñar un contador de 0 a 10E10-1(98967FH ) con señal de reset asíncrono (ACLR) y fin de cuenta (THRESH0), para acceder a estas opciones se debe seleccionar el botón Next. Figura 10: Plantilla de los contadores. Una vez parametrizado el componente se crea actuando sobre Generate, creandose el archivo VHDL. A su vez se crea un archivo, de extensión vho, que proporciona las lineas de código para definir y instanciar el componente en un archivo VHDL. El contenido del fichero de plantilla prescaler.vho es: -- This file is owned and controlled by Xilinx and must be used --- solely for design, simulation, implementation and creation of --- design files limited to Xilinx devices or technologies. Use --- with non-Xilinx devices or technologies is expressly prohibited --- and immediately terminates your license. ----- Xilinx products are not intended for use in life support --- appliances, devices, or systems. Use in such applications are --- expressly prohibited. ----- Copyright (C) 2001, Xilinx, Inc. All Rights Reserved. ------------------------------------------------------------------------ The following code must appear in the VHDL architecture header: ------------- Begin Cut here for COMPONENT Declaration ------ COMP_TAG component prescaler port ( Q: OUT std_logic_VECTOR(23 downto 0); CLK: IN std_logic; THRESH0: OUT std_logic; ACLR: IN std_logic); end component; -- COMP_TAG_END ------ End COMPONENT Declaration ------------- The following code must appear in the VHDL architecture -- body. Substitute your own instance name and net names. ------------- Begin Cut here for INSTANTIATION Template ----- INST_TAG your_instance_name : prescaler port map ( Q => Q, CLK => CLK, THRESH0 => THRESH0, ACLR => ACLR); -- INST_TAG_END ------ End INSTANTIATION Template ---------------- You must compile the wrapper file prescaler.vhd when simulating the core, prescaler. When compiling the wrapper file, be sure to reference the XilinxCoreLib VHDL simulation library. For detailed instructions, please refer to the "Coregen Users Guide". 2.2. MÓDULO BCD2SEG. -10- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín El modelo del decodificador BCD a 7 segmentos se almacena en el fichero bcd2seg.vhd. La decodificación se realiza mediante una asignación concurrente de señal seleccionada tal y como se muestra en el siguiente listado. La salida de este módulo es un bus de 7 líneas donde la de menor peso corresponde al segmento “a” y la de mayor peso al segmento “g”. library ieee; use ieee.std_logic_1164.all; entity BCD2SEG is port ( BCD: in Display:out end BCD2SEG; std_logic_vector(3 downto 0); -- input data std_logic_vector(6 downto 0)); architecture inside of BCD2SEG is begin with BCD select Display <= "0111111" "0000110" "1011011" "1001111" "1100110" "1101101" "1111101" "0000111" "1111111" "1100111" "0000000" end inside; when when when when when when when when when when when "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", others; --0 --1 --2 --3 --4 --5 --6 --7 --8 --9 --0 2.3. MÓDULO CRONO.VHD Este es el fichero principal del diseño sobre el que se instancian los componentes bcd2seg y prescaler. El resto de los módulos que aparecen en el diagrama de bloques de la figura 1.4 (contador, registros, FSM, etc) aparecerán como procesos dentro de la arquitectura del cronometro. El listado completo de este fichero se muestra a continuación. library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity crono is port ( lapso: rst: clk: in in in std_logic; std_logic; std_logic; DisplayUnidades: out std_logic_vector(6 downto 0); DisplayDecenas: out std_logic_vector(6 downto 0)); attribute pull:string; attribute pull of rst,lapso:signal is "pullup"; end crono ; architecture rtl of crono is -- Declaración del decodificador BCD a 7 segmentos. component BCD2SEG port( BCD: in std_logic_vector (3 downto 0); Display: out std_logic_vector (6 downto 0)); end component; -- Declaración del prescaler (COREGEN). component prescaler port ( Q: OUT std_logic_VECTOR(23 downto 0); CLK: IN std_logic; THRESH0: OUT std_logic; ACLR: IN std_logic); end component; signal Unidades: signal Decenas: signal CntUnidades: signal CntDecenas: signal EN1HZ,rst_n: std_logic_vector(3 downto 0); std_logic_vector(3 downto 0); unsigned(3 downto 0); unsigned(3 downto 0); std_logic; -- Estados de la FSM que controla el sistema. type stateFSM is ( -11- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. S1, S2, S3, S4); ----- signal state: signal actualizar: RunningWaitingOnPush RunningWaitingOnRelease FrozenWaitingOnPush FrozenWaitingOnRelease stateFSM; std_logic; begin -- Instantación de los decodificadores BCD a 7 segmentos. U1 : BCD2SEG BCD DISPLAY port map ( => Unidades, => DisplayUnidades); U2 : BCD2SEG BCD DISPLAY port map ( => Decenas, => DisplayDecenas); -- Instantación del prescaler (COREGEN). U3 : prescaler port map ( CLK => clk, THRESH0 => EN1HZ, ACLR =>rst_n); rst_n<= not rst; -- Proceso contador. process(clk,rst) begin if(rst='0') then CntUnidades <= (others => '0'); CntDecenas <= (others => '0'); elsif(clk='1' and clk'event) then if(EN1HZ='1') then if (CntUnidades = 9) then CntUnidades <= (others => '0'); if (CntDecenas = 5) then CntDecenas <= (others => '0'); else CntDecenas <= CntDecenas + 1; end if; else CntUnidades <= CntUnidades + 1; end if; end if; end if; end process; -- Proceso de registros de lapso. process(clk,rst) begin if(rst='0') then Unidades <= (others => '0'); Decenas <= (others => '0'); elsif (clk'event and clk='1') then if (actualizar = '1') then Unidades <= std_logic_vector(CntUnidades); Decenas <= std_logic_vector(CntDecenas); end if; end if; end process; -- Maquina de estados de control del lapso: -Control del cambio de estados. process(clk,rst) begin if(rst='0') then state <= S1; elsif (clk'event and clk='1') then case state is when S1 => if (lapso = '1') then state <= S1; else state <= S2; end if; when S2 => if (lapso = '0') then state <= S2; else state <= S3; end if; when S3 => if (lapso = '1') then state <= S3; else state <= S4; end if; when S4 => if (lapso = '0') then state <= S4; else state <= S1; end if; end case; end if; end process; -12- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín -- Maquina de estados de control del lapso: -Control de la salida. process(state) begin case state is when S2 | S3 => actualizar <= '0'; when S1 | S4 => actualizar <= '1'; end case; end process; end rtl ; 2.3.1. Declaración de librerías. Este fichero comienza con la declaración de las librerías a emplear. El paquete numeric_std contiene la declaración de tipos y operadores que permiten realizar operaciones aritméticas con vectores de bits. 2.3.2. Definición de la entidad. Respecto a la declaración de la entidad la única cuestión a destacar sobre lo ya expuesto es la asignación del atributo pull a los puertos correspondientes a los pulsadores. Este atributo es reconocido automáticamente por el sintetizador como indicador de que debe emplear la resistencia de pull-up de los IOBs correspondientes a dichos puertos. Esto se verá con más detalle en el apartado dedicado al sintetizador. 2.3.3. Parte declarativa de la arquitectura. En esta parte del código se declaran los componentes a instanciar (decodificadores BCD a 7 segmentos y el prescaler creado con COREGEN) así como las señales internas empleadas para conectar los distintos elementos que aparecen en el diagrama de bloques de la figura 1.4. También aparece un tipo enumerado empleado en la descripción de la señal de estado de la FSM. 2.3.4. Instanciación de componentes. Al principio del cuerpo de la arquitectura se realiza la instanciación de los componentes mencionados. Así el puerto clk se conecta a la entrada de reloj del prescaler, obteniéndose su salida la señal EN1Hz, utilizada para habilita la cuenta del contador. 2.3.5. Contador de décadas. Este contador se implementa mediante el proceso cuyo listados se muestra a continuación. Dicho proceso es sensible a las señales de reset asíncrona (rst) y reloj (clk) . El carácter asíncrono de la señal de reset se fija mediante la posición de la sentencia if dentro de la estructura de if anidados que evalúa su estado. El valor de cuenta se almacena sobre las señales CntUnidades y CntDecenas. Estas señales están declaradas de tipo unsigned. Este es un tipo derivado de std_logic_vector que permite realizar operaciones aritméticas. El valor de cuenta sólo se modifica si la señal EN1HZ está a 1. Esta señal se obtiene del módulo prescaler. -- Proceso contador. process(clk,rst) begin if(rst='0') then CntUnidades <= (others => '0'); CntDecenas <= (others => '0'); elsif(clk='1' and clk'event) then if(EN='1') then if (CntUnidades = 9) then CntUnidades <= (others => '0'); if (CntDecenas = 5) then CntDecenas <= (others => '0'); -13- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. else end if; else end if; end process; end if; end if; CntDecenas <= CntDecenas + 1; CntUnidades <= CntUnidades + 1; 2.3.6. Registros de la visualización. Los registros empleados para implementar la función de congelación de la visualización se describen mediante el siguiente proceso. process(clk,rst) begin if(rst='0') then Unidades <= (others => '0'); Decenas <= (others => '0'); elsif (clk'event and clk='1') then if (actualizar = '1') then Unidades <= std_logic_vector(CntUnidades); Decenas <= std_logic_vector(CntDecenas); end if; end if; end process; Si la señal actualizar correspondiente a la salida de la FSM está a uno (visualización no congelada) las señales Unidades y Decenas reflejan el valor de cuenta en cada flanco activo de la señal de reloj. Las cuales se conectan a las entradas de los decodificadores BCD a 7 segmentos. Hay que destacar que estas señales son de tipo std_logic_vector mientras que las señales de cuenta CntUnidades y CntDecenas son de tipo unsigned. Por este motivo es preciso emplear una conversión “cast” en la asignación. 2.3.7. Máquina de estados. La figura 1.11 muestra el diagrama de bloques de una máquina de estados. Como se aprecia ésta se describe mediante sendos procesos: uno para controlar las transiciones entre estados y otro para generar la salida de la máquina. Entradas asíncronas Proceso síncrono Entradas Próximo estado Cálculo del próximo estado Lógica combinacional Reloj Elementos de memoria Lógica secuencial Entradas (sólo para tipo Mealy) Estado actual Cálculo de las salidas. Salidas Lógica combinacional Proceso combinacional Figura 11: Estructura de una máquina de estados. Para representar el estado de la máquina se ha definido el tipo enumerado stateFSM que puede tomar los valores correspondientes a dichos estados. El valor del estado actual de la FSM se almacena en la señal state. La salida de la FSM es la señal actualizar que toma el valor cero cuando la cuenta está congelada. Para declarar estas señales se emplea el siguiente código: -14- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín type stateFSM is ( S1, -- RunningWaitingOnPush S2, -- RunningWaitingOnRelease S3, -- FrozenWaitingOnPush S4); -- FrozenWaitingOnRelease signal state: signal actualizar: stateFSM; std_logic; El proceso empleado para modelar las transiciones entre estados es sensible a las señales de control asíncronas (rst) y reloj (clk). La decodificación del siguiente estado en función del estado actual y las entradas se realiza mediante una sentencia case. El código VHDL de este proceso es el siguiente -- Maquina de estados de control del lapso: -Control del cambio de estados. process(clk,rst) begin if(rst='0') then state <= RunningWaitingOnPush; elsif (clk'event and clk='1') then case state is when S1 => if (lapso = '1') then state <= S1; else state <= S2; end if; when S2 => if (lapso = '0') then state <= S2; else state <= S3; end if; when S3 => if (lapso = '1') then state <= S3; else state <= S4; end if; when S4 => if (lapso = '0') then state <= S4; else state <= S1; end if; end case; end if; end process; El proceso empleado para modelar la lógica combinacional empleada para generar las salidas es sensible al estado de la FSM. Si se tratará de una máquina de tipo Mealy en esta lista deberían declararse también las entradas de la FSM. -- Maquina de estados de control del lapso: -Control de la salida. process(state) begin case state is when S2 | S3 => actualizar <= '0'; when S1 | S4 => actualizar <= '1'; end case; end process; 2.4. BANCO DE PRUEBAS. A continuación se proporciona el listado del fichero VHDL correspondiente al banco de pruebas empleado para validar el diseño. Se trata de una entidad sin puertos. En la parte declarativa de la arquitectura se declara el componente a verificar (crono) y un conjunto de señales correspondientes a cada uno de los puertos de dicho componente. Éstas son fácilmente reconocibles porque tienen el sufijo _tb. -15- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. library IEEE; use ieee.std_logic_1164.all; entity testbench is generic ( PUSHTIME: time := 500 ns; -- Tiempo de duración de una tecla. RSTTIME: time := 10 ns; -- Tiempo de activación del reset. Tclk: time := 100 ns); -- Periodo de la señal de reloj. end testbench; architecture simula of testbench is -- Declaración del componente crono. component crono port ( lapso: in std_logic; rst: in std_logic; clk: in std_logic; DisplayUnidades: out std_logic_vector(6 downto 0); DisplayDecenas: out std_logic_vector(6 downto 0)); end component; begin -- Señales auxiliares para de excitación para el banco de pruebas. signal lapso_tb: std_logic; signal rst_tb: std_logic:='0'; signal clk_tb: std_logic:='0'; signal DisplayUnidades_tb: std_logic_vector(6 downto 0); signal DisplayDecenas_tb: std_logic_vector(6 downto 0); -- Instantación del componente crono. uut : crono port map ( lapso => lapso_tb, rst => rst_tb, clk => clk_tb, DisplayUnidades => DisplayUnidades_tb, DisplayDecenas => DisplayDecenas_tb); -- Generación de la señal de reset. rst_tb <= '1' after RSTTIME; -- Generación de la señal de reloj. clk_tb <= not clk_tb after Tclk/2; -- Proceso principal control de la excitacion. process --------------------------------------------------------- PULSAR: Simula la pulsación del pulsador de lapso -- Parámetros de entrada: -No tiene. --------------------------------------------------------procedure pulsar is begin lapso_tb <= '0'; wait for PUSHTIME; lapso_tb <= '1'; wait for PUSHTIME; end pulsar; begin -- Valor inicial de los estímulos. lapso_tb <= '1'; -- Secuencia de operación. wait for 1 ms; pulsar; wait for 10 ms; pulsar; wait for 10 ms; pulsar; -- Termina la simulación. assert FALSE report "Finalizacion controlada de la simulacion" severity failure; end process; end simula; El control de la introducción de estímulos propiamente dicha se realiza mediante un proceso. En él se declara un procedimiento para cada una de las acciones a llevar a cabo en la verificación del diseño. En este ejemplo el procedimiento pulsar reproduce la pulsación de la tecla lapso. En el cuerpo del proceso se controla el instante en que se realiza cada acción (ejecución del proceso asociado) mediante sentencias wait for. Notese que este proceso no tiene lista de sensibilidades por lo que se estaría ejecutando siempre. Para controlar la finalización de la simulación desde el propio banco de pruebas se emplea la sentencia assert. 2.5. FICHERO CNF_FUNCIONAL.VHD -16- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín Co el fín de que el testbench creado pueda ser utilizado tanto para realizar una simulación funcional como temporal se deben crear sendas configuraciones, que nos permitan seleccionar arquitecturas diferentes para el componente crono. En el caso de realizar la simulación funciona, para el componente cronol instanciado en el testbench, se debe se debe seleccionar la arquitectura rtl . El código del archivo de configuración es el siguiente: configuration funcional of testbench is for simula for dut : crono use entity work.crono(rtl); end for; end for; end funcional ; Todas las cuestiones anteriores referidas a la configuración de componentes son innecesarias si a la hora de referenciar el componente crono en el testbench, se utiliza la referencia a componente de VHDL-93, en la cual se puede referenciar un componente sin ser previamente declarado en la parte declarativa de la arquitectura y en la cual puede especificarse la entidad y la arquitectura a usar. En el caso de utilizar esta alternativa será necesario crear dos archivos de testbench, uno para realizar la simulación funcional y otro para la temporal, si bien el contenido sería el mismo. La única diferencia estaría en la instanciación del componente, así en el testbench de para la simulación funcional se pondría: dut : entity work.crono(rtl) port map ( lapso => lapso_tb, rst => rst_tb, clk => clk_tb, DisplayUnidades => DisplayUnidades_tb, DisplayDecenas => DisplayDecenas_tb); El listado completo del testbench para realizar la simulación temporal utilizando la anterior declaración de componente se encuentra en el archivo tb_funcional.vhd. También se aporta un nuevo scrip para la compilación de todo el diseño, caso de utilizar el anterior testbench. Dicho archivo scrip es compila2.do. Así mismo, se añade el archivo sim_funcional2.do para realizar la simulación funcional. 3. SIMULACIÓN FUNCIONAL DEL DISEÑO. 3.1. INTRODUCCIÓN. Para verificar la validez del diseño realizado se realizará una simulación de funcional (también denominada de comportamiento o RT) empleando para ello el simulador ModelSim de Mentor Graphics. Para ello arranque el simulador seleccionando Inicio º Programas º ModelSim SE EE º ModelSim En ese momento se muestra la pantalla que aparece en la figura 1.12. -17- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. Figura 12: Pantalla del simulador VHDL. Este simulador se puede controlar mediante una interface gráfica de usuario basada en menús y cajas de diálogo desplegables o bien mediante una línea de comandos. En este tutorial se explicará el uso del simulador mediante comandos. Esta decisión se basa en el hecho de que el interface de usuario puede variar de una versión a otra, no ocurriendo esto con los comandos. Concretamente para realizar este tutorial se ha empleado la versión 5.5c, por lo que algunas de las ventanas mostradas pueden variar ligeramente. La secuencia de comandos a emplear para realizar una simulación se pueden almacenar en un fichero de script. Conceptualmente los ficheros de scripts son similares a los ficheros de proceso por lotes de un sistema operativo (por ejemplo .bat para DOS). Se les suele asignar la extensión .do. Para ejecutar un fichero de script se emplea el comando do cuya sintaxis es: do <nombre_fichero_script> La posibilidad de almacenar estas secuencias de comandos en ficheros de script permite reutilizarlos en los distintos tipos de simulación a realizar (funcional, post-implementación y temporal) durante el flujo de diseño VHDL para FPGAs. 3.1.1. Librerías. Las librerías son directorios que contienen unidades de diseño compiladas. Estas unidades de diseño pueden ser primarias o secundarias. Las unidades de diseño primarias (entidades, declaraciones de paquetes y configuraciones) almacenadas en una librería deben tener un nombre único. Por otro lado las unidades de diseño secundarias (arquitecturas y cuerpos de paquetes) pueden tener nombres comunes. Por ejemplo, las arquitecturas de dos entidades distintas pueden tener el mismo nombre. Este simulador clasifica las librerías en dos tipos: librerías de trabajo y librerías de recursos. Todo diseño dispone de una única librería de trabajo que por defecto se denomina work, donde se almacenan una vez que se han compilado las unidades de diseño descritas en los ficheros fuente del -18- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín diseño. La librería de trabajo debe crearse antes de compilar los ficheros fuente del diseño. Por otro lado las librerías de recursos contienen unidades de diseño a las que se puede hacer referencia desde diseño que se está compilando. Estas librerías se declaran mediante las sentencias library y use. Así para nuestro ejemplo, la entidad y arquitectura del cronómetro se almacena en la librería work mientras que el componente OSC4 se encuentra almacenado en la librería unisim. Para crear una librería se utiliza el comando vlib. La sintaxis de este comando es: vlib <library_name> donde <library_name> es el nombre de la librería. Este comando crea el directorio asociado a dicha librería en el directorio de trabajo actual. Una vez creada la librería se pueden proceder a compilar los ficheros fuente VHDL que contienen la descripción de las unidades de diseño que se almacenarán en dicha librería. Para ello se emplea el comando vcom. La sintaxis resumida de este comando es: vcom [-93] [-work <nombre_librería>] <fichero1>.vhd <fichero2>.vhd ... El parámetro -93 indica que se emplee el la versión 93 de VHDL frente a la 87. Si no se especifica este parámetro se emplea la versión especificada mediante la opción Options º Compile... de la barra de menús. Mediante el parámetro -work se especifica la librería destino en la que se almacenará el código compilado. Si no se especifica este parámetro por defecto se almacena en la librería work. Recuerdese que la librería destino debe haber sido creada con anterioridad y en caso de que no se encuentre en el directorio actual haber sido hecha visible mediante el comando vmap. Por último se especifican los ficheros VHDL a compilar. Éstos se compilan en el orden de aparición. El orden en que se especifican los ficheros fuente dependerá de las dependencias existentes entre las unidades de diseño descritas en ellos. Según esto se debe compilar: ! ! ! ! ! ! La entidad antes que la arquitectura. La declaración del paquete antes que el cuerpo de éste. Las unidades de diseño antes de las referencia a ellas. Los paquetes antes que las entidades/arquitecturas que los utilicen. Las entidades/Configuraciones antes de las arquitecturas a que hacen referencia. Las configuraciones se compilan las últimas. Puede ocurrir que el directorio donde se almacena una librería no este contenido en el directorio de trabajo actual. Esta es una situación típica que se da cuando se pretenden utilizar unidades de diseño compiladas con anterioridad para otro diseño en el diseño actual. Por ejemplo, las librerías unisim, simprim y xilinxcoregenlib se reutilizarán en cada nuevo diseño para FPGAs de Xilinx. Para gestionar estas situaciones ModelSim asigna a cada librería un nombre físico y un nombre lógico. El nombre físico corresponde al path del directorio donde se almacenan las unidades de diseño compiladas. El nombre lógico es la denominación que recibe la librería cuando se hace referencia a ella desde el simulador o desde el código fuente VHDL, por ejemplo mediante la sentencia use. Cuando una librería se encuentra almacenada en el directorio de trabajo actual el nombre físico coincide con el nombre lógico. En caso contrario es preciso asignar a la librería un nombre lógico mediante el comando vmap. A este proceso se le denomina mapeado. La sintaxis de este comando es: vmap <nombre_logico> <path_del_directory> -19- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. Otros comandos empleados para la gestión de librerías son vdir y vdel que se emplean respectivamente para mostrar el contenido de una librería y para borrar elementos de ésta. La sintaxis de vdir es: vdir [-lib <nombre_librería>] Si se emplea el comando sin parámetros se muestra el contenido de la librería work. Por otro lado la sintaxis del comando vdel es: vdel [-lib <nombre_librería>] [-all |<unidad_de_diseño>] donde <nombre_librería> es la librería de donde se desea borrar la unidad de diseño en cuestión. Si no se especifica la librería se toma por defecto la librería work. En cuanto a las unidades de diseño a borrar éstas se pueden especificar individualmente o bien borrar todas ellas utilizando el parámetro -all. En este último caso se borra incluso el directorio correspondiente a la librería por lo que si se desean compilar con posterioridad nuevos ficheros fuente sobre ésta será preciso crearla de nuevo con el comando vlib. Al igual que ocurre en los compiladores de C, los cuales proporcionan en la librería de soporte del sistema las funciones definidas por ANSI C, los simuladores VHDL suelen disponer de una serie de librerías predefinidas que no es necesario compilar cada vez que se realiza un nuevo diseño. En el caso concreto de ModelSim se encuentran predefinidas las siguientes librerías: ! ! ! La librería std que contiene los paquetes standard y textio. La librería IEEE que contiene paquetes aritméticos precompilados de Synopsys e IEEE. La librería vital empleada para realizar simulaciones temporales. Estas librerías están optimizadas para la simulación por lo que no es recomendable que el usuario realice modificaciones de ellas. Teniendo en cuenta lo expuesto, siguiendo con nuestro ejemplo se procederá a crear las librerías VHDL de Xilinx (unisim, simprim y XilinxCoreLib) y compilarlas. Para ello cree el directorio donde se almacenarán estas librerías. Por ejemplo: c:\VHDL_Xilinx_lib El código fuente de estas librerías se encuentra en c:\ise41\vhdl\src. Dentro de este directorio se encuentran tres subdirectorios correspondientes a cada una de las librerías citadas. Para compilar las librerías cambie el directorio actual del simulador al directorio donde se almacenarán ejecutando desde la consola de ModelSim el comando: cd c:/VHDL_Xilinx_lib Notese que la sintaxis empleada por ModelSim para especificar la jerarquía de un directorio es la misma que la de Unix, ya que las primeras versiones de este simulador se desarrollaron para dicho sistema operativo. Para crear estas librerías se deben ejecutar los siguientes comandos desde la consola de ModelSim: ! Compilación de la librería unisim. vlib unisim vcom -work unisim C:/ise41/vhdl/src/unisims/unisim_VPKG.vhd -20- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín vcom -work unisim C:/ise41/vhdl/src/unisims/unisim_VCOMP.vhd vcom -work unisim C:/ise41/vhdl/src/unisims/unisim_VITAL.vhd vmap unisim c:/VHDL_Xilinx_lib/unisim ! Compilación de la librería simprim. vlib vcom vcom vcom vmap ! simprim -work simprim C:/ise41/vhdl/src/simprims/simprim_Vpackage.vhd -work simprim C:/ise41/vhdl/src/simprims/simprim_Vcomponents.vhd -work simprim C:/ise41/vhdl/src/simprims/simprim_VITAL.vhd simprim c:/VHDL_Xilinx_lib/simprim Compilación de la librería XilinxCoreLib. vlib XilinxCoreLib vcom -work XilinxCoreLib C:/ise41/vhdl/src/XilinxCoreLib/mvlutil.vhd vcom -work XilinxCoreLib C:/ise41/vhdl/src/XilinxCoreLib/mvlarith.vhd vcom -work XilinxCoreLib C:/ise41/vhdl/src/XilinxCoreLib/XilinxCoreLib.vhd vmap XilinxCoreLib c:/VHDL_Xilinx_lib/XilinxCoreLib Para facilitar el trabajo junto con el código fuente del diseño se proporcionan un fichero script xilinx_lib.tcl que permite realizar las operaciones anteriores de una manera más simple. La ejecución del script se realiza mediante el comando source.: source xilinx_lib.tcl una vez ejecutado aparece la ventana mostrada en la figura 1.13. Se deben seleccionar las opciones que aparecen en dicha figura, pudiendose variar el subdirectorio destino. Figura 13: Configuración de las librerías. La creación de las estas librerías sólo se realiza una vez, es decir, no es preciso compilar estas librerías para cada nuevo diseño a realizar. Ademas el archivo de inicialización de ModelSim es modificado de forma que dichas librerías serán siempre visibles para posteriores diseños. 3.2. MANEJO DEL SIMULADOR. Los pasos a dar para realizar una simulación son los siguientes. Ø Ù Ú Creación del proyecto. Creación de nuevas librerías y mapeado de las librerías a reutilizar. Compilación del código fuente. -21- Ingeniería Electrónica. Û Ü Ý Þ ß ô Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. Carga de la unidad de diseño a simular. Definición de puntos de prueba. Avance y detención de la simulación. Introducción de estímulos. Análisis de resultados. Finalización de la sesión de simulación. 3.2.1. Creación del proyecto. Al igual que ocurre con otros entornos de desarrollo ModelSim gestiona la información de cada diseño mediante un proyecto, facilitando de esta forma su gestión. Un proyecto se compone de: ! ! ! ! Un directorio de trabajo en el que se almacenan los distintos ficheros generados durante la compilación y simulación de un diseño. Los ficheros fuente VHDL del diseño. Las librerías creadas. La configuración empleada en el simulador. Esta información se almacena en un fichero con el mismo nombre que el proyecto y la extensión .mpf. Las operaciones que se pueden realizar con un proyecto son crearlo, abrirlo, cerrarlo o borrarlo. Estas se realizan mediante las opciones New, Open, Close y Delete del menú File. Para crear el proyecto empleado para realizar la simulación funcional del diseño del ejemplo seleccione la opción File º New º Project de la barra de menús. En ese momento se mostrará en la pantalla la ventana Create Project. Configure las opciones de estas ventana tal y como se muestra la figura 1.14. Con esto se creará automáticamente el subdirectorio behavioral dentro del directorio c:\tutorial. Además crea automáticamente la librería work definiendola como la librería de trabajo para este nuevo diseño. Por tanto, el path de esta librería será c:/tutorial/behaviral/work. Figura 14: Ventana de creación de proyecto. Si bien el empleo de proyectos no es obligatorio su uso facilita la gestión del diseño. En caso de no desear emplear esta facilidad habría que ejecutar los siguientes comandos: cd c:/tutorial mkdir behavioral cd behavioral vlib work -22- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín 3.2.2. Creación de nuevas librerías y mapeado de las librerías a reutilizar Si se desea compilar alguno de los ficheros fuente sobre alguna librería distinta de work será preciso crearla previamente con el comando vlib. De igual forma si dentro de nuestro código se hace referencia a alguna librería creada con anterioridad será preciso mapearla mediante el comando vmap. Claro está que esto no es aplicable a las librerías predefinidas del simulador. Así, para hacer visibles las librerías de Xilinx en un diseño se emplearían los siguientes comandos: vmap unisim c:/VHDL_Xilinx_lib/unisim vmap simprim c:/VHDL_Xilinx_lib/simprim vmap XilinCoreLib c:/VHDL_Xilinx_lib/XilinCoreLib Conviene aclarar que cuando se realiza el mapeado de una librería, el simulador almacena esta información en el fichero de descripción del proyecto, de forma que se mantenga esta configuración la próxima vez que se abra el proyecto. El simulador considera esta configuración como un aspecto general siendo aplicable a todos aquellos proyectos que se creen a partir de ese momento. Para ello almacena la información de mapeado en el fichero de configuración general denominado modelsim.ini. Este fichero se encuentra en el directorio donde ha sido instalado ModelSim. En tal caso, en dicho fichero deben aparecer las siguientes líneas: simprim = C:/VHDL_Xilinx_lib/simprim unisim = C:/VHDL_Xilinx_lib/unisim XilinCoreLib = C:/VHDL_Xilinx_lib/XilinCoreLib En el caso de este tutorial no es necesario mapear la librerías de Xilinx ya que esa labor se ha realizado con la ejecución del scrip xilinx_lib.tcl. Otra forma sencilla de verificar si las librerías son visibles para el proyecto actual es mediante la opción Design º Browse Libraries de la barra de menús tal y como muestra la figura 1.15. En caso de que no aparezcan las librerías citadas será preciso realizar el mapeado de éstas. Figura 15: Ventana de listado de librerías. 3.2.3. Compilación del código fuente. -23- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. Una vez creado el proyecto se procederá a la compilación de los ficheros VHDL que forman parte del diseño. Por defecto las unidades de diseño se almacenarán en la librería work. Si un fichero VHDL proporciona una unidad de diseño que será utilizada en otro fichero el primero de ellos debe compilarse en primer lugar. Para compilar los ficheros fuente del diseño se han de ejecutar los siguientes comandos desde la consola de ModelSim: vcom vcom vcom vcom vcom -93 -93 -93 -93 -93 bcd2seg.vhd prescaler.vhd crono.vhd testbench.vhd cnf_funcional.vhd El fichero script compila.do recoge estos comandos. Por tanto se debe ejecutar el comando: do compila.do Durante la compilación el simulador muestra en la consola información referente a la evolución de ésta. Si aparecen errores, la descripción de estos se muestra en color rojo. Haciendo doble click sobre la línea de error se muestra automáticamente la línea del fichero fuente que produjo este error en la ventana de código fuente. En la figura 1.16 aparece un ejemplo de ésto. Figura 16: Visualización automática de errores en el código fuente. 3.2.4. Carga de la unidad de diseño a simular Para poder simular el diseño realizado es preciso cargarlo en el simulador. Para ello se emplea el comando vsim. El formato resumido de este comando es: vsim [-lib <nombre_librería>] [-t [múltiplo]<unidades_tiempo>] -24- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín [-sdfmin | -sdftyp | -sdfmax <instancia>=<fichero_sdf>] <entidad> [<arquitectura>] | <configuración> Como se puede observar todos los parámetros son opcionales excepto el último de ellos que indica la unidad de diseño superior. Este último indica la entidad a simular, siendo posible especificar también la arquitectura concreta a emplear. Esto resulta especialmente útil cuando la entidad dispone de varias arquitecturas. Por ejemplo si se deseara simular únicamente el decodificador bcd a 7 segmentos el comando a emplear sería: vsim work.BCD2SEG inside o bien simplemente vsim BCD2SEG La librería que contiene la unidad de diseño a simular también se puede especificar mediante el parámetro opcional -lib. Si no se especifica, por defecto se supone que dicha unidad se encuentra almacenada en la librería de trabajo. El parámetro -t indica la resolución de la simulación. Dicha resolución se especifica en unidades de tiempo según el formato indicado en la tabla 1.1. Adicionalmente puede emplearse un factor multiplicador siendo los valores admisibles 1, 10 o 100. Si no indica la resolución del simulador, por defecto este trabaja con una resolución de 1 ns. Tabla 1.1: Nomenclatura empleada para especificar unidades de tiempo. Unidades Valor Unidades Valor fs 10-15 sg ms 10-3 sg ps 10-12 sg sec segundos ns 10-9 sg min minutos us 10-6 sg hr horas Para el caso de una simulación temporal de un diseño para FPGAs teniendo en cuenta que los retardos internos se expresan con una resolución de 0.1 ns la opción a emplear para fijar la resolución sería -t 100ps. Notese que no hay espacios en blanco entre el multiplicador y las unidades. Por último el parámetro -sdfxxx sólo se usa en simulaciones temporales, empleandose para especificar el fichero sdf que contiene la retroanotación de retardos. Por este motivo su explicación detallada se pospondrá al apartado destinado a simulaciones temporales. Según lo expuesto, una vez compilados los ficheros fuente del diseño de nuestro ejemplo se puede proceder a cargar la unidad de diseño a simular. Para nuestro ejemplo ésta es la configuración ConfBehavioral, por lo que el comando a emplear será: vsim cnf_funcional 3.2.5. Selección de puntos de prueba. La verificación del diseño mediante simulación se basa en observar los distintos elementos que aparecen en éste. Por analogía con un simulador digital clásico a los puntos del circuito a observar (señales) los denominaremos puntos de prueba, si bien en diseños descritos en VHDL la variedad es más amplia: variables, señales, procesos en ejecución, etc.Tal -25- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. y como muestra la figura 1.17 el simulador define un total de ocho ventanas destinadas a representar los distintos tipos de elementos. Estas ventanas son: ! ! ! ! ! ! ! structure. Muestra la estructura jerárquica del diseño en forma de árbol. En nivel seleccionado en esta ventana afectará al contenido de las ventanas de formas de onda, variables, etc. source. Muestra la el código fuente del diseño. Se suele emplear para ejecutar el código paso a paso. signal. Muestra las señales contenidas en el nivel seleccionado en la ventana de estructura. process. Proporciona información del estado de ejecución de los procesos. wave. Permite representar los cronogramas de la evolución de las señales y variables del diseño. dataflow. La ventana de flujo de datos permite realizar un seguimiento gráfico de la conexión de procesos mediante las señales del diseño. list. La ventana de listado permite observar los resultados de la simulación de forma tabular y reflejando los ciclos delta Figura 17: Ventanas del simulador. Para abrir una de estas ventanas se emplea el comando view cuyo formato es: view <nombre_ventana> Este comando admite el carácter comodín *. Así el siguiente comando abre todas las ventanas citadas: view * -26- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín La descripción detallada del uso de todas las ventanas queda fuera de los objetivos de este texto. Por este motivo sólo se expondrá el uso de la ventana de formas de onda, al ser éste el método más empleado para depurar sistemas digitales mediante simulación. Para abrir esta ventana seleccione la opción View º Wave de la barra de menús, o bien ejecute el comando: view wave A continuación es preciso seleccionar las señales a visualizar. Si el número de señales a visualizar es elevado esta operación puede ser un tanto tediosa. En ese caso se puede optar por realizar esta operación mediante el interface gráfico. Para ello es preciso abrir las ventanas de estructura y de señales. La primera de ellas nos servirá para navegar por la estructura jerárquica del diseño, mientras que la segunda nos permitirá seleccionar las señales a añadir a la ventana de formas de onda. Para abrir la ventana de estructura seleccione la opción View º Structure de la barra de menús, o bien ejecute el comando: view structure De forma similar, para abrir la ventana de señales seleccione la opción View º Signal de la barra de menús, o bien ejecute el comando: view signal Tal y como muestra la figura 1.18 al seleccionar un nivel en la ventana de estructura, se muestran todas las señales contenidas en dicho nivel sobre la ventana de formas de onda. Figura 18: Selección de las señales de un determinado nivel jerárquico. Una vez mostradas las señales de interés en la ventana de señales se procederá a añadirlas a la ventana de formas de onda. Para ello se seleccionan las señales en cuestión en la ventana de señales y a continuación se elige la opción View º Wave º Selected Signals de la barra de menús. O de una forma más simple, se seleccionan y se arrastran hasta la ventana wave. Una vez finalizado este proceso la ventana de formas de onda presenta el aspecto mostrado en la figura 1.19. -27- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. Figura 19: Ventana wave una vez seleccionadas las señales a visualizar. También es posible representar en la ventana de formas de onda la evolución de las variables de los procesos. Para ello es preciso que el proceso al que pertenece la variable a visualizar esté etiquetado. Esta etiqueta sirve como elemento identificador dentro de la ventana de estructura. El proceso a seguir es el mismo que el utilizado para seleccionar las señales, pero utilizando la ventana de variables. El color de las señales, el formato numérico utilizado en el caso de los vectores, etc. se puede fijar mediante las distintas opciones del menu sensible al contexto que aparece al seleccionar una señal determinada y pulsar a continuación el botón derecho del ratón (o con Format de la barra de menús). La configuración utilizada en la ventana de formas de onda puede almacenarse en un fichero de scripts denominado wave.do para volverla a utilizar en posteriores sesiones de simulación (por ejemplo cuando se realice la simulación temporal). Para ello seleccione la opción Fileº Save Format de la barra de menús. Básicamente, este fichero contiene comandos del tipo add wave, los cuales se utilizan para añadir señales o variables a la ventana de formas de onda. Su sintaxis resumida es: add wave [-<format>] [-<radix>] <nombre_elemento> El parámetro <nombre_elemento> especifica el nombre de la variable o señal a visualizar. Si dicho elemento no se encuentra en la entidad superior de la jerarquía se debe indicar el camino completo dentro de ésta. En el caso de las variables, se especificará el camino hasta la arquitectura donde reside el proceso que contiene la variable. El parámetro opcional radix especifica la base numérica con que se representan los vectores. Los valores que puede tomar este parámetro son binary, octal, decimal (o signed), unsigned, hexadecimal, ascii, symbolic o default. Puesto que estos nombres son suficientemente ilustrativos hay poco que añadir a este respecto. Tan sólo indicar, que la opción -symbolic se emplea con tipos enumerados. Si no se indica nada se representa según la base numérica fijada por defecto (-default) en las opciones del simulador. El parámetro opcional format indica el formato de representación (numérico o gráfico) a emplear de los vectores. Los valores que puede tomar son literal, logic, analog-step, analog-interpolated y analog-backstep. Normalmente esta opción no se suele emplear, dejando que estos los vectores se representen en formato numérico. Las tres últimas opciones permiten -28- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín representar la secuencia de valores que toma el vector como las muestras de una señal analógica digitalizada. Esto es especialmente útil en la implementación de sistemas de tratamiento digital de señal. La figura 1.20 muestra un ejemplo de esto. Figura 20: Ejemplo de representación analógica de señales. Una descripción más detallada de los formatos analógicos, como de los digitales, se encuentra en el manual del simulador, al que se puede acceder desde Help de la barra de menús. En el ejemplo de diseño considerado, para analizar el funcionamiento del sistema se van a observar los puertos del cronómetro, las señales de cuenta (clkla y EN1HZ) y el estado de la presentación (señal actualizar). A la hora de especificar una señal es preciso indicar el camino completo dentro de la jerarquía. Según esto los comandos a ejecutar serían: add add add add add add add add add add wave wave wave wave wave wave wave wave wave wave /testbench/rst_tb /testbench/clk_tb /testbench/dut/en1hz /testbench/lapso_tb /testbench/dut/state /testbench/dut/actualizar -unsigned /testbench/dut/cntunidades -unsigned /testbench/dut/cntdecenas /testbench/displayunidades_tb /testbench/displaydecenas_tb Tal y como se ha indicado una forma sencilla de obtener estos comandos es realizar una selección manual y a continuación generar el fichero de configuración wave.do, de este último se extraen las variables que queremos visualiza, y se añaden al archivo scrip para la simulación. Téngase presente que el formato de los comandos add wave tienen diferente contenido al mostrado anteriormente, por lo que, si el usuario lo considera pertinente puede retocarlos, para tener una sintaxis más corta, si bien la semántica sigue siendo la misma. A continuación se muestran estos comandos tal y como se encuentran en el archivo wave.do. -29- Ingeniería Electrónica. add add add add add add add add add add wave wave wave wave wave wave wave wave wave wave Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. -noupdate -noupdate -noupdate -noupdate -noupdate -noupdate -noupdate -noupdate -noupdate -noupdate -format -format -format -format -format -format -format -format -format -format Logic /testbench/rst_tb Logic /testbench/clk_tb Logic /testbench/dut/en1hz Logic /testbench/lapso_tb Literal /testbench/dut/state Logic /testbench/dut/actualizar Literal -radix unsigned /testbench/dut/cntunidades Literal -radix unsigned /testbench/dut/cntdecenas Literal /testbench/displayunidades_tb Literal /testbench/displaydecenas_tb Los comandos utilizados para cargar el diseño a simular y configurar la ventana de formas de onda se recogen en el script sim_funcional.do proporcionado. 3.2.6. Avance y detención de la simulación. Para provocar un avance de la simulación se emplea el comando run, siendo su sintaxis: run[<magnitud>[<unidades_tiempo>]] | <modo> El tiempo a avanzar en la simulación se puede especificar de varias formas, de acurdo a una serie de modos predeterminados. Una primera especificación del tiempo de simulación es: run[<magnitud>[<unidades_tiempo>]] En este formato se avanza el tiempo especificado por el parámetro. Este tiempo se da como un valor numérico seguido de unas unidades de tiempo empleando para ello el formato descrito en la tabla 1.1. Si no se especifican las unidades se entiende que el tiempo viene expresado en la resolución del simulador (por defecto es 1ns). Por ejemplo, el siguiente comando provocaría un avance en la simulación de 400 ns: run 400ns Otra forma de emplear el comando run responde al formato: run<modo> donde el parámetro <modo> puede ser uno de los siguientes valores: ! ! ! ! ! -all Ejecuta la simulación indefinidamente hasta que ésta se detenga debido a un punto de ruptura o a un error de simulación (sentencia assert). -step Avanza la simulación hasta la siguiente sentencia VHDL. -stepover Es exactamente igual que la anterior salvo que las llamadas a procedimientos o funciones se tratan como una única sentencia, ejecutandose de una vez. -continue Continua la simulación desde el punto en que se detuvo debido a un punto de ruptura. -next Ejecuta la simulación hasta el siguiente evento. Según esto el comando: run -all -30- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín ejecutaría la simulación del ejemplo hasta que se detuviera debido a la línea del fichero testbench: assert FALSE report "Finalizacion controlada de la simulacion" severity failure; Para reiniciar la simulación, volviendo el tiempo a 0 ns, e iniciar una nueva simulación se emplea el comando restart. Al ejecutar este comando aparece la ventana mostrada en la figura 1.21. En ella se puede seleccionar qué elementos mantendrán la configuración fijada durante la sesión de simulación actual. Figura 21: Ventana Restart. Si durante la sesión de simulación se descubre un error de diseño que obliga a modificar el código fuente será preciso finalizar la simulación mediante el comando quit -sim. A continuación se modifica el código fuente, se compila y se vuelve a cargandolo de nuevo tal y como se ha descrito. 3.2.7. Introducción de estímulos. Normalmente los estímulos del diseño se introducen mediante el código del fichero de banco de pruebas o testbencs. Sin embargo en un diseño típico el sistema está compuesto por varios módulos más sencillos que se instanciarán en el diseño final. Antes de obtener el diseño final será preciso validar los módulos que lo componen. La realización de un banco de pruebas para cada uno de estos módulos tan sencillos puede resultar una tarea tediosa. Para solventar esta situación se puede emplear el comando force, que permite introducir estímulos sobre las señales resueltas del diseño de una forma sencilla. La sintaxis general de este comando es: force <nombre_señal> <valor1> <tiempo1>, <valor2> <tiempo2> ... Con este formato se introducen los estímulos especificados en pares (valor, instante de tiempo) para la señal en cuestión. Cuando se trata de una señal interna en el nombre se debe especificar el camino completo en la jerarquía del diseño. Los valores a asignar a una deben ajustarse al tipo de datos de misma. Los instantes de tiempo pueden expresarse en formato relativo al instante actual de simulación o en valor absoluto respecto al origen de tiempos (t=0). En este último caso se ha de añadir el prefijo @. Por defecto las unidades en que se expresan los tiempos coincide con la resolución del simulador (ns). Existe un conjunto de parámetros adicionales que permiten introducir estímulos periódicos. Estos son: -repeat <periodo> Repite el comando force con el periodo de tiempo especificado. -31- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. -cancel <tiempo> Cancela el comando force una vez transcurrido el tiempo especificado. A continuación se muestran varios ejemplos del uso de este comando. force clr 0 Fuerza clr a 0 en el instante actual de simulación. force bus1 01XZ 100 ns Fuerza bus1 a 01XZ 100 ns después del instante actual de simulación. force bus2 16#4F @200 Fuerza bus2 a 4Fh 200 unidades de tiempo (especificadas por la resolución de simulación) desde el inicio de ésta. force clk 0 0, 1 25 -repeat 50 Genera una señal de periodo 50 ns con un ciclo de trabajo del 50% force clk 0 0, 1 20 -repeat 50 -cancel 1000 Fuerza clk a 0 en el instante actual de simulación, 20 unidades de tiempo después pasa a 1. Esto se repite cada 50 unidades de tiempo hasta alcanzar 1000 unidades de tiempo. Por tanto el siguiente 1 ocurrirá en la unidad de tiempo 70. Según lo expuesto para validar de forma individual el módulo prescaler se emplearía la siguiente secuencia de comandos: vsim work.prescaler add add add add wave wave wave wave /prescaler/aclr /prescaler/clk /prescaler/q /prescaler/thresh0 force aclr 1 0, 0 20 force clk 0 0,1 10 -repeat 20 Como se ha comentado este comando se emplea para aplicar estímulos a señales resueltas. En el caso de que se aplique un estímulo a una señal interna del diseño, la función de resolución determinará el estado que toma esta señal. Existe un modo de operación de este comando denominado “modo congelado” que permite imponer un valor a una señal interna. Esto es especialmente útil para reducir el tiempo de simulación de un diseño. Así, en el diseño considerado la salida del sistema cambia cada segundo, por lo que para verificar el diseño se precisaría mucho tiempo de simulación. Para reducirlo se forzará la salida del prescaler (señal EN1Hz) a 1 mediante el comando: force -freeze testbench/dut/EN1HZ 1 En el caso de utilizar la opción freeze con un comando force, para desactivarla se debe ejecutar en comando noforce. Por ejemplo para el caso anterior se utilizaría: noforce testbench/dut/EN1HZ 1 Resumiendo, para realizar la simulación del diseño se introducirá la secuencia de comandos que se indica a continuación. Esta secuencia se encuentra almacenada en el fichero de script sim_funcional.do proporcionado. -32- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín # scrip de simulacion destroy .wave vsim work.cnf_funcional # Definicion de se¤ales a visualizar. add add add add add add add add add add wave wave wave wave wave wave wave wave wave wave /testbench/rst_tb /testbench/clk_tb /testbench/dut/en1hz /testbench/lapso_tb /testbench/dut/state /testbench/dut/actualizar -unsigned /testbench/dut/cntunidades -unsigned /testbench/dut/cntdecenas /testbench/displayunidades_tb /testbench/displaydecenas_tb run 400 ns force -freeze testbench/dut/EN1HZ 1 run 50 us Para realizar la simulación funcional del diseño, es algo tan sencillo como ejecutar el comando: do sim_funcional.do La figura 1.22 muestra el aspecto de la pantalla de cronogramas obtenida al ejecutar el comando anterior, donde se puede comprobar el funcionamiento correcto del diseño. Figura 22: Resultado de la simulación del cronómetro. 3.2.8. Análisis de resultados. En este apartado se comentará como navegar por la ventana de cronogramas así como la realización de mediciones de tiempos. Para ajustar el zoom de la visualización se emplean las cuatro lupas que aparecen en la barra de herramientas: ! Zoom de acercamiento. ! Zoom de alejamiento. ! Amplia una zona de los cronogramas. -33- Ingeniería Electrónica. ! Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. Muestra la totalidad de los cronogramas. Para realizar medidas de tiempo se emplean los cursores, un cursor se añade con el elemento . La primera vez que se pulsa este botón aparece el cursor principal, que tal y como muestra la figura 1.23, éste aparece como una línea azul de trazo grueso. Los cursores se pueden situar de forma manual pulsando directamente sobre un punto de los cronogramas. En este caso el cursor se sitúa sobre la transición más próxima al punto seleccionado. Si se desean desplazar los cursores hasta la siguiente transición de la señal seleccionada se emplean los botones . Esto es especialmente útil para las medidas de tiempos. Las mediciones de tiempo se realizan utilizando un segundo cursor, para ello se sitúan el cursor principal y el secundario sobre las dos transiciones, de la misma u otra señales. Estas transiciones delimitan el tiempo a medir. El segundo cursor se añade de igual forma que el primero, mostrándose en trazo discontinuo. El tiempo medido se muestra en la parte inferior de la pantalla. Finalmente para eliminar estos cursores se emplea el botón . Figura 23: Medida de tiempos. 3.2.9. Finalizar la sesión de simulación. La simulación de un diseño permite comprobar el correcto funcionamiento del mismo. Desde que se crean un diseño hasta que se van a realizar varias simulaciones hasta depurar y obtener el código correcto, por lo que será preciso finalizar la sesión de simulación, modificar el código fuente, compilar y volver a simular. Para finalizar la sesión de simulación se emplea el comando quit -sim. Notese que el finalizar la sesión de simulación no supone cerrar ModelSim. El uso de este comando tiene su interés cuando el código VHDL hace uso de ficheros. Una práctica muy habitual es emplear fichero del cual se toma la secuencia de estímulos (vectores de test) a aplicar al diseño. Por ejemplo en el caso de sistemas de tratamiento digital de señal implementados en FPGAs, el bando de pruebas puede obtener los datos a procesar desde un fichero previamente creado mediante Matlab. De forma similar los resultados del procesamiento se pueden almacenar en un fichero de salida para su posterior análisis. En este caso, el simulador abre el ficheros de salida al cargar la unidad de diseño a simular, manteniendo el control sobre éste por lo que no se puede acceder a su contenido hasta que no finalice la sesión de simulación. En ese momento el fichero de salida puede abrirse con otra herramienta. -34- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín 3.3. PUNTOS DE RUPTURA. Una de las posibilidades más empleadas en los simuladores son los puntos de ruptura (breakpoints). ModelSim permite trabajar con dos tipos de puntos de ruptura. El primero de ellos se fija sobre las líneas de código de la ventana de código fuente (source). Este tipo de puntos de ruptura se asemeja al empleado por los depuradores de software. Para activar un punto de ruptura de este tipo basta con pulsar con el ratón sobre la línea en la que queremos poner el punto de ruptura. Para desactivarlo basta con una nueva pulsación. Cuando se ejecuta la línea de código marcada se detiene la simulación. Esto también se puede realizar mediante el comando bp. El formato empleado es: bp <nombre_fichero> <número_de_línea> El segundo formato, denominado condicional, se asemeja al concepto empleado por un simulador digital, permitiendo asociarlo a señales., para ello se utiliza el comando when, cuya sintaxis es: when [-label <nombre>] {<expresión_condición>} {<acción>} El parámetro -label asigna el identificador <nombre> al punto de ruptura definido. El parámetro <expresión_condición> define la condición a evaluar en el punto de ruptura. Cuando esta expresión es cierta se dispara el punto de ruptura. La sintaxis de esta expresión responde al siguiente formato: subexpresión1 operador_lógico subexpresión2 operador_lógico subexpresión3... Las subexpresiones vienen dadas por operadores relacionales y atributos de detección de eventos. Los siguientes ejemplos muestran las situaciones admitidas. ! ! ! Igualdad. Desigualdad Detección de eventos: clk = ’1' ó clk==’1' bus1 /= “0000" clk’EVENT Los operadores de igualdad y desigualdad sólo admiten como segundo parámetro un literal, es decir no se puede comparar el estado de dos señales. Los operadores lógicos que ligan las subexpresiones pueden ser el operador and o el operador or. En la expresión condicional se admite el empleo de paréntesis para establecer la prioridad con que se evalúan las distintas subexpresiones. El parámetro <acción> define la secuencia de comandos a del simulador a ejecutar cuando se dispara el punto de ruptura. Este parámetro es opcional, si no se indica la acción a realizar consiste en detener la simulación. Por ejemplo, para simular el prescaler se podría utilizar los siguientes el siguientes comandos force aclr 1 0, 0 20 force clk 0 0,1 10 -repeat 20 run 30 when -label pto1 { thresh0'event} {stop} run -all -35- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. De forma, la simulación se realizará hasta que se detecte una transición en la señal thresh0, o lo que es lo mismo cuando thresh0 pase a ‘1'. Para borrar un punto de ruptura de este tipo se emplea el comando nowhen, cuya sintaxis es: nowhen <identificador> Por ejemplo para borrar el punto de ruptura definido en el ejemplo se emplea el comando: nowhen pto1 3.4. METODOLOGÍA DE TRABAJO. En la descripción realizada a cerca del manejo del simulador se ha hecho especial incapié en su uso mediante comandos, obviandose el uso del interface gráfico. Aparentemente el uso de comandos puede parecer más complejo debido al esfuerzo inicial que supone la creación de estos ficheros. Pero hay que tener en cuenta que en raras ocasiones se obtiene a la primera un diseño totalmente correcto. En tal caso la verificación del diseño mediante simulación se convierte en un proceso iterativo consistente en modificar el código fuente, compilarlo, simular y observar los resultados. Mediante el uso de ficheros de scripts esto se reduce a seleccionar mediante el “doskey” de la consola la secuencia de comandos: do compila.do do simula.do quit -sim .... do compila.do A esto hay que añadir que este esfuerzo inicial que supone la creación de los ficheros de script se ve recompensado por la facilidad de poder reutilizarlos. Así los scripts creados para la simulación funcional se pueden reutilizar con leves modificaciones en la simulación temporal. Además en su formato básico no varían demasiado de un diseño a otro, por lo que también se suelen reutilizar en este caso. 3.5. UTILIZACIÓN DEL INTERFACE GRÁFICO Como se comentó con anterioridad, los diferentes comando también se pueden seleccionar por los iconos o elementos de la barra de herramientas. A continuación se van a ver algunos de ello. Permite selecciona el o los archivo a compilar (comando vcom). Cuando se activa se accede a la pantalla de la figura 1.24, donde se selecciona el archivó VHDL a compilar. Haciendo uso de las teclas SHIFT y CTRL se pueden seleccionar más de un archivo, teniendo en cuenta que se deben seleccionar en orden ascendente de la jerarquía -36- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín Figura 24: Compilación de archivos VHDL. Un campo importante de la figura anterior es el de las Default Options (figura 1.25), donde se selecciona, entre otras cosas , el estándar VHDL utilizado. Figura 25: Opciones de compilación. Permite seleccionar la unidad VHD a simular (comando vsim). Cuando se selecciona se accede a la pantalla de la figura 1.26, donde se selecciona la unidad a simular. -37- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. Figura 26: Selección de la unidad de diseño a simular. En la barra de herramientas se encuentran otros iconos que permiten controlar el avance del tiempo del simulador, a continuación se detallan: Permite selecciona la cantidad de tiempo que avanza la simulación cuando se ejecuta el comando run. run. run -continue run -all Parar la simulación (break). run - step run - step over restart Merece la pena hacer incapie en la utilización del menú help para acceder a una colección de archivos en formato pdf que van desde un manual de ModelSim hasta la explicación de la semántica y sintaxis de todos los comandos. 4. SÍNTESIS DEL DISEÑO. -38- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín Una vez realizada la simulación funcional del diseño descrito en VHDL se procederá a sintetizarlo. Para ello se empleará como herramienta de síntesis VHDL el sintetizador Leonardo Spectrum de Exemplar. 4.1. OPERACIÓN INTERNA DEL SINTETIZADOR. Antes de proceder a la síntesis del diseño se mostrará el funcionamiento interno de este sintetizador. Esto facilitará la compresión de su manejo. Tal y como muestra la figura 1.28 la síntesis RTL se divide en las siguientes fases: ! ! ! análisis. elaboración. optimización. Jerarquía del diseño Diseño RTL a nivel de puertas. Análisis de caminos críticos. Optimización temporal .work .work Análisis Diseño VHDL compilado en memoria Elaboración RTL (diseño con puertas genéricas) OPTIMIZACIÓN Diseño mapeado en la tecnología destino DISEÑO EN MEMORIA ESCRITURA LECTURA VHDL VHDL EDIF XNF Ficheros de lista de conexiones de salida. EDIF Ficheros fuente. Diseño en celdas de la tecnología destino. HERRAMIENTAS SIMULADOR DE IMPLEMENTACIÓN VHDL Figura 28: Proceso de síntesis. Durante la fase de análisis se verifica la sintaxis del fichero VHDL, se comprueban las dependencias y se resuelven los genéricos que pudieran aparecer en el código fuente. A partir de los ficheros analizados el sintetizador construye una base de datos interna del diseño. Si alguno de los ficheros fuente hace referencia a elementos que aperecen en librerías o paquetes propios del diseñador estos deben ser procesados previamente. Muchas librerías y paquetes standard están integrados en el propio sintetizador y no necesitan ser procesados explícitamente. En la fase de elaboración, se sintetiza el código VHDL en una lista de conexiones compuesta por funciones lógicas genéricas y cajas negras asociadas a los operadores. Estas funciones lógicas genéricas son primitivas propias del sintetizador (no de la FPGA), a partir de las cuales se construye el diseño sintetizado. Se trata pues, de un formato intermedio previo al mapeado tecnológico en el que estas primitivas se sustituirán por las celdas propias de la tecnología destino. Esto permite que una misma herramienta de síntesis se pueda utilizar con distintas tecnologías destino. Posteriormente, estas cajas negras asociadas a operadores se sustituirán con operadores implementados específicamente para la tecnología destino. En -39- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. muchas ocasiones es el propio fabricante de los dispositivos para los que se sintetiza el circuito el que proporciona estos operadores en forma de una librería de macroceldas parametrizables. Este tratamiento diferenciado que se da a los operadores se debe a que las herramientas de síntesis no son muy eficientes a la hora de procesar la lógica aritmética y relacional (denominada normalmente lógica del data path). Esto es especialmente cierto para las FPGAs, donde cada tecnología destino tiene distintas formas de optimizar el uso de sus recursos internos. Un diseño VHDL puede estar formado por uno o varios ficheros fuente VHDL. Además muchos sintetizadores permiten incorporar partes del diseño como componentes descritos mediante una lista de conexiones en la que aparecen celdas de la tecnología para la que se va a sintetizar. Estos componentes se instanciarán en el código fuente VHDL donde se vayan a utilizar mediante descripciones estructurales. Los sintetizadores pueden admitir formatos de listas de conexiones standard como EDIF, o propios de la herramienta de implementación de la tecnología para la que se va a sintetizar. Un ejemplo de esto último es el formato XNF de Xilinx. La posibilidad de describir parte del diseño en este formato permite reutilizar partes de un diseño anterior realizado mediante esquemas. Para ello sería necesario generar una lista de conexiones en formato XNF de estos esquemas. Para facilitar la migración de estos diseños algunos sintetizadores como Express de Synopsys disponen además de bibliotecas de macros expresadas como listas de conexiones en formato XNF que corresponden a las macros que aparecen en las librerías de captura de esquemas. Internamente los sintetizadores almacenan los datos de un diseño en librerías cuyo formato depende de la cada herramienta. Así la herramienta “Leonardo Spectrum” utiliza un formato similar al EDIF. La forma en que las distintas partes del diseño se almacena es estas librerías internas es la siguiente: ! Librería de la tecnología destino. Al fijar en el sintetizador la tecnología destino para la que se va a sintetizar, éste carga automáticamente una librería que contiene todas las celdas de esa tecnología. Los componentes contenidos en esta librería pueden ser instanciados en el código VHDL para sacar partido a las características de la arquitectura del dispositivo para el que se va a sintetizar. Un ejemplo de esto sería el uso del oscilador interno de la familia Spartan XL de Xilinx. ! Librerías de trabajo. Al cargar una descripción VHDL o una parte del diseño expresada como una lista de conexiones las entidades contenidas en éstas quedan almacenadas por defecto en la librería work, si bien es posible, si se desea, definir otra librería como destino. ! Librería de primitivas. El sintetizador crea automáticamente una librería de primitivas que contiene todas las funciones lógicas básicas o primitivas que emplea el sintetizador cuando compila o elabora el código VHDL. Mediante diseño estructural se pueden instanciar estos componentes independientes de la tecnología (aunque dependen del sintetizador empleado). Librería de operadores. El sintetizador también crea una librería de operadores. Esta librería contiene celdas de operadores (sumadores, multiplicadores, multiplexores, etc). Al compilar una descripción VHDL estos operadores se generan cuando es preciso. ! Una vez finalizada la síntesis RT, se procede a realizar la síntesis lógica. En esta fase, las herramientas de síntesis permiten imponer restricciones temporales al diseño. Estas restricciones pueden controlar el proceso de mapeado tecnológico y la optimización. Durante la optimización se persigue -40- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín la obtención de implementaciones con el menor área posible y el cumplimiento de restricciones temporales en aquellos caminos críticos en que han sido fijadas estas restricciones, dando lugar a un sistema rápido y que ocupa los menos posibles recursos de la FPGA. También es posible imponer restricciones topológicas que permitan guiar a la herramienta de implementación durante el proceso de emplazamiento e interconexionado. Por ejemplo, desde la propia herramienta de síntesis se puede asignar los pads que infieren los puertos de la entidad de nivel superior a terminales del dispositivo sobre el que se va a implementar el diseño. Finalmente el sintetizador genera una lista de conexiones, es decir, un modelo estructural que contiene solamente referencias a celdas lógicas de la tecnología destino. Esta lista de conexiones será utilizada por la herramienta de implementación para realizar el emplazamiento e interconexión y de esta forma proceder a la implementación del diseño sobre un dispositivo físico. No existe un formato standard para esta lista de conexiones, pero el más extendido es el formato EDIF. Algunas herramientas de síntesis para FPGAs producen listas de conexiones en un formato propio de la tecnología para la que se está sintetizando. Tal es el caso del sintetizador Leonardo Spectrum que puede generar una lista de conexiones en formato .XNF para posteriormente compilarlo con las herramientas de implementación de Xilinx, aunque éstas también interpretan el formato EDIF. Por otra parte, es posible que el sintetizador genere esta lista de conexiones como una descripción estructural VHDL lo que validar el resultado de la síntesis con los mismos bancos de prueba utilizados con la descripción RTL original. Es lo que normalmente se conoce como simulación post-síntesis pre-implementación. Ciertos aspectos del proceso de síntesis se pueden controlar mediante directivas que aparecen en el propio código fuente. Se trata de directivas que aparecen como comentarios de forma que sólo son reconocidas por el sintetizador siendo ignoradas por los simuladores. A este tipo de directivas se les denomina pragma (comentarios sintéticos o metacomentarios). Su formato depende de cada herramienta de síntesis en particular, por ejemplo: -- synopsys translate_off ......... -- synopsys translate_on En otras ocasiones se emplean atributos para controlar el proceso de síntesis. Cada sintetizador define sus propios atributos. Al analizar el código fuente VHDL, el sintetizador reconoce automáticamente dichos atributos operando según proceda. Por ejemplo, Leonardo Spectrum al detectar el atributo pull aplicado sobre un puerto de entrada instancia una resistencia de pull-up o pull-down entre el IPAD y el IBUF asociado a dicho puerto. El tipo de resistencia a emplear depende del valor del atributo. Por ejemplo, para fijar una resistencia de pull-up en los puertos de los pulsadores de nuestro diseño se emplearía el siguiente código: attribute pull:string; attribute pull of rst,lapso:signal is "pullup"; 4.1.1. Generadores de módulos. -41- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. Como se ha comentado anteriormente las herramientas de síntesis no son eficientes a la hora de procesar la lógica aritmética y relacional aparece en el data path, siendo especialmente problemático en el caso de FPGAs, donde cada tecnología tiene una forma distinta de optimizar implementación de estos operadores. muy que las la Con el fín de obtener resultados óptimos, el diseñador podría optar por utilizar macros hard (p.e. módulos generados mediante COREGEN) o soft (ficheros de listas de conexiones) proporcionadas por el fabricante de FPGAs para implementar este tipo de lógica. Esta macro aparecería como un componente instanciado en el código fuente. Sin embargo la instanciación de componentes plantea los siguientes inconvenientes: ! ! ! La descripción del diseño deja de ser comportamental. El código VHDL se convierte en dependiente de la tecnología. La instanciación de componentes no está permitida en la definición de operadores o funciones. Normalmente los sintetizadores disponen de generadores de módulos incorporados que proporcionan al diseñador un mecanismo de sobrecarga de los operadores del data path, como por ejemplo para las funciones “+”, “-” y “>”, con implementaciones prediseñadas específicas de una tecnología. Esta generación se realiza atendiendo al tamaño (número de elementos) de los operandos. Normalmente los sintetizadores soportan los siguientes operadores: ! ! ! ! ! ! Multiplicador (operador * ). Sumador, restador y sumador/restador (operadores + y -). Incremento, decremento e incremento/ decremento (operadores + y -). Complemento a dos (operador unario -). Comparador (operadores relacionales <, <=, >, >=, =, /=, ==, !=). Multiplexor (estamentos de selección). Puesto que los algoritmos de generación de módulos son específicos para cada familia de FPGAs soportada, las prestaciones y el área de estos módulos se optimizan específicamente para dicha arquitectura, igualando los resultados obtenidos con las macros proporcionadas por el fabricante. Al mismo tiempo, permite al diseñador describir la lógica con un estilo de comportamiento puro. El hecho de que estos módulos sean generados por el propio sintetizador le permite optimizar la lógica obtenida junto con la que aparece alrededor del módulo, con lo que la lógica resultante es menor y más rápida. Esto no es posible con macros hard ya que dichos componentes aparecen como cajas negras en el código sintetizado. Además el sintetizador puede aplicar algoritmos de compartición de recursos, con lo que se puede optimizar aún más el circuito. La figura 1.29 muestra el flujo de datos general en el entorno de generación de módulos. Una vez que se ha analizado con éxito el código fuente, se pasa al motor de inferencia que compara los operadores soportados con las implementaciones prediseñadas de la librería de generación de módulos. Cada vez que se encuentra en el código fuente un operador soportado, se consulta la librería de generación de módulos específicos de la tecnología. Si se encuentra una implementación, se utiliza en el diseño. En caso contrario, el sintetizador proporciona la implementación lógica por defecto de ese operador. Por ejemplo, si no se dispusiera de un módulo del operador suma para la tecnología destino, se podría generar un sumador con acarreo serie mediante lógica combinacional. -42- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín Código fuente VHDL Analizador sintáctico VHDL. Motor de inferencia para generación de módulos. genéricos módulo Librería de generación de módulos Síntesis, optimización y mapeado. Lista de conexiones para FPGA Figura 29: Generador de módulos. 4.2. MANEJO DEL SINTETIZADOR. Una vez descrita la forma en que opera internamente el sintetizador, se pasará a exponer la forma de utilizar esta herramienta. Para ejecutar el sintetizador seleccionese la opción: Inicio º Programas º LeonardoSpectrum º LeonardoSpectrum mostrandose la ventana que muestra la figura 1.30. Esta ventana permite fijar el nivel de operación del sintetizador. El nivel de operación determina el control que tendrá el usuario sobre el proceso de síntesis: a mayor nivel mayor control. Figura 30: Selección del nivel de operación. Seleccione el nivel 3 y pulse el botón OK. Con esto se entra en la ventana principal del sintetizador cuyo aspecto se muestra en la figura 1.31. -43- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. Barra de menús Barra de herramientas Pestañas de flujo Ventana de flujo de diseño Ventana de comandos Línea de estado Figura 31: Ventana principal del sintetizador. Los principales elementos que aparecen en esta ventana son: ! Una barra de menús desde la que es posible seleccionar las distintas opciones que controlan el funcionamiento del sintetizador. ! Una barra de herramientas que permite acceder directamente a las opciones que se emplean con mayor frecuencia. ! Una línea de estado. Proporciona cierta información como el estado del sintetizador, directorio de trabajo, etc. ! Una ventana de flujo de diseño con la que controlan las distintas fases del proceso de síntesis y se fijan las opciones de éstas. Cada fase tiene una pestaña asociada. Con esta ventana se realiza la síntesis mediante un interface gráfico. ! Ventana de comandos. Otra forma de controlar el proceso de síntesis es mediante la ejecución de comandos. De hecho ésta es la forma básica de operación del sintetizador mientras que la ventana de flujo de diseño es un mero “caparazón” gráfico desde que se invocan los comandos necesarios. La ventana de comandos se divide en dos partes. La parte inferior es una consola desde la que se introducen los comandos, mientras que la información referente a su evolución se muestra en la parte superior de esta ventana. Como se ha comentado, el proceso de síntesis se puede controlar mediante una interface gráfica (ventana de flujo de diseño) o mediante comandos (ventana de comandos). El uso de uno u otro método depende de las preferencias personales de cada usuario. En cualquier caso es obvio que el primer método resulta más intuitivo pero permite un control menos exhaustivo del proceso de síntesis y resulta tedioso su manejo cuando la complejidad del diseño es elevada. Algunos diseñadores aducen en contra del empleo de comandos que resulta complicado aprenderse toda una serie de nuevos comandos. A este respecto hay que indicar que para un control básico del proceso de síntesis, el conjunto de comandos a emplear es bastante reducido, siendo posible además almacenar la secuencia de comandos a emplear en un fichero de scripts y -44- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín ejecutarlos conjuntamente tal y como se hizo en el simulador. Por estos motivos se expondrá el manejo del sintetizador mediante comandos, describiendo los comandos a emplear en cada una de las fases del proceso de síntesis. En el caso de que el usuario opte por la ejecución de la síntesis desde el interface gráfico, a medida que se ejecuta cada herramienta en la ventana de comandos se van listando los comandos a los que corresponde dicha herramienta, con lo que con una simple operación de selección y copy-pastes, se puede obtener de una forma sencilla el scrip para la síntesis. 4.2.1. Inicialización del sintetizador. Para sintetizar un nuevo diseño en primer lugar es preciso inicializar el sintetizador, borrando el contenido de las librerías internas y fijando el directorio de trabajo actual. Esta operación se realiza mediante el comando: clean_all El directorio de trabajo actual para nuestro ejemplo será c:/tutorial/. 4.2.2. Selección de la tecnología destino. En primer lugar es preciso cargar la librería de la tecnología destino (familia Spartan2 de Xilinx), seleccionando a continuación el dispositivo en concreto para el que se va a sintetizar (XC2S50TQ144), la velocidad de éste (-6) y la estimación de retardos debidos a interconexiones (ésta se calcula en función del número de entradas conectadas a cada salida pudiendose dar como valor promedio o para el peor caso). Esta información temporal es empleada durante la optimización del diseño. Una forma sencilla de realizar estas operaciones es mediante el uso del interface gráfico. Para ello seleccione la herramienta de síntesis avanzada pulsando el botón de la barra de herramientas. Tal y como se muestra en la figura anterior, mediante la pestaña Technology se pueden seleccionar las opciones citadas. Con el árbol que aparece a la izquierda se selecciona la familia en cuestión (familia Spartan2 de Xilinx), la opción Device se emplea para seleccionar el dispositivo (XC2S50TQ144), el grado de velocidad se fija con la opción Speed (-6) y finalmente la opción Wire Load la forma de estimar los retardos debidos a interconexiones. Una vez realizadas estas operaciones, al pulsar el botón Load Library se desencadena la ejecución de los comandos necesarios para configurar el sintetizador. Esta secuencia de comandos se muestra en la ventana de comandos. De entre todos los comandos mostrados (existen algunos cuyo uso es irrelevante) los que realizan las operaciones mencionadas son: load_library xisxl set part S10xlPC84 set process 4 set wire_table s10xl-4_avg 4.2.3. Selección del método de codificación de las máquinas de estados. El lenguaje VHDL no define la forma en que se codifican los tipos enumerados. Si el diseño contiene máquinas de estado es preciso indicar como se codificará el tipo enumerado que define el estado de la máquina. Estas cuestiones relacionadas con el funcionamiento interno del sintetizador se pueden configurar mediante variables o atributos internos de la -45- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. herramienta. Como es lógico, estas variables y atributos internos dependen de cada herramienta en cuestión, variando de unas a otras. Las variables internas se emplean su uso debe afectar a la totalidad del diseño, fijandose el valor de dichas variables mediante el comando set. Por otro lado, los atributos internos se emplean cuando su uso debe afectar a un elemento concreto del diseño (p.e. un tipo enumerado, una señal, un componente, etc). En este caso el comando a emplear se denomina set_attribute. La mayoría de los atributos internos del sintetizador (¡no todos!) se pueden fijar en el propio código fuente. Un ejemplo de esto es el atributo pull utilizado en el ejemplo para fijar las resistencias de pull-up de los pulsadores. Volviendo a la cuestión del tipo de codificación de los tipos enumerados, este sintetizador soporta los siguientes tipos de codificación: ! Binario. Genera máquinas de estados con el menor número de biestables posible. ! Gray. Con este tipo de codificación sólo conmuta un biestable en las transiciones de la máquina. ! Aleatorio (ramdom). Asigna los códigos de estado de forma aleatoria. Este tipo sólo se debe utilizar si los restantes tipos no proporcionan los resultados adecuados. ! One Hot. Con este tipo de codificación se emplea un biestable para cada estado de la máquina, proporcionando las mejores prestaciones en cuanto a consumo de recursos y máxima frecuencia de funcionamiento. Si bien el número de biestables empleado en la codificación one-hot es mayor que en la binaria, es preferible su uso en dispositivos programables cuya arquitectura dispone de un gran número de biestables. Tal es el caso de las FPGAs de Xilinx. Para fijar de forma global el tipo de codificación se emplea la variable el comando set encoding cuyo formato es: set encoding <tipoo donde tipo puede ser binary, onehot, twohot, gray, random o auto. Por ejemplo para seleccionar una codificación one hot en nuestro ejemplo se emplea el comando: set encoding onehot Para indicar de forma explícita la codificación utilizada por un determinado tipo de datos se utiliza el atributo es TYPE_ENCODING. De esta forma es posible asignar individualmente el código a cada estado de la máquina. Antes de asignar este atributo al tipo enumerado es preciso declararlo. Así para nuestro ejemplo, si se desea asignar el código 00 al estado S1, el 01 al S2, el 11 al S3 y 10 al S4 se emplearía el siguiente código: -46- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín .. -- Declaración del atributo TYPE_ENCODING: type exemplar_string_array is array (natural range <>,natural range <>) of character; attribute TYPE_ENCODING : exemplar_string_array ; -- Estados de la FSM que type stateFSM is ( S1, S2, S3, S4); signal state: stateFSM; controla el sistema. ----- RunningWaitingOnPush RunningWaitingOnRelease FrozenWaitingOnPush FrozenWaitingOnRelease -- Asignación del atributo type-encoding. attribute TYPE_ENCODING of state:type is ("00","01","11","10") ; ... 4.2.4. Lectura de ficheros del diseño. Una vez seleccionada la tecnología destino para la que se va a sintetizar, se han de leer los ficheros VHDL que componen el diseño. El orden en que se leen estos ficheros dependerá de las dependencias que existen entre ellos. Así si uno de ellos define una unidad de diseño que es utilizada en otro de ellos el primero de ellos debe leerse antes que el segundo. Por tanto el orden de lectura suele coincidir con la posición que ocupan en la jerarquía del diseño, leyendose en primer lugar el de nivel inferior. Según esto para el ejemplo considerado el comando a emplear es: read {../BCD2SEG.vhd ../crono.vhd} Notese que no se indican ni los ficheros de los módulos COREGEN (son modelos de simulación), ni los del banco de pruebas y el fichero de configuración asociado (soló se emplea en simulación para introducir los estímulos al diseño). Al realizar la lectura de un fichero el sintetizador analiza el código fuente. Si aparece algún mensaje de error este aparece marcado con un circulo rojo en la parte superior de la ventana de comandos. Haciendo doble click con el ratón sobre dicho círculo aparece una ventana que muestra el código fuente que produjo dicho error. La figura 1.32 muestra esto. Esto mismo es aplicable a los avisos (warnings), salvo que en este caso el círculo es de color azul. Figura 32: Búsqueda automática de errores en el código fuente. Para seleccionar de los archivos, mediante el interface gráfico se utiliza la pestaña Imput( ), apareciendo la ventana de la figura 1.33 -47- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. Figura 33: Selección de archivos. Con las pestañas Work Directory y Open files se seleccionan los archivos VHDL a sintetizar, utilizando para ello un orden creciente en la jerarquía de diseño. A continuación se selecciona el tipo de codificación para los estados de las máquinas de estados (Encoding Style). Para finalizar se pulsa la pestaña read. 4.2.5. Selección del diseño actual. Los distintos ficheros leídos proporcionan unidades de diseño que el sintetizador almacena internamente en las librerías de trabajo (por defecto work). Antes de realizar la síntesis propiamente dicha es preciso indicar el par entidad-arquitectura de mayor jerarquía del diseño que se va a sintetizar. La sintaxis empleada es: nombre_librería.nombre_entidad.nombre_arquitectura. Según esto para nuestro diseño el comando a emplear será: present_design .work.cronometro.inside 4.2.6. Configuración de opciones de optimización. Una vez leídos los ficheros que componen el diseño estos se analizan y elaboran. El siguiente paso consistiría en realizar la optimización de la síntesis. Previamente a esta última operación habrá que fijar las restricciones a aplicar al proceso optimización. Al igual que ocurre con el tipo de codificación de los tipos enumerados las restricciones se pueden aplicar de forma global mediante variables internas o de forma particular mediante atributos internos. Las restricciones impuestas desde el sintetizador se exportan a las herramientas de implementación mediante un fichero de restricciones en formato nativo (.ncf) que acompaña a la lista de conexiones que genera el sintetizador. Como se ha comentado estas restricciones pueden ser topológicas o temporales. Un ejemplo del primer caso consistiría en la asignación del IOB asociado a -48- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín un puerto de la entidad de mayor jerarquía a un terminal concreto de la FPGA. Para esto se puede emplear el siguiente comando: set_attribute -port {.work.cronometro.inside.rst} -name PIN_NUMBER -value P28 En cualquier caso, ha de destacarse que este tipo de restricciones también es posible aplicarlas desde la herramienta de implementación de Xilinx mediante un fichero de restricciones de usuario (.ucf). La elección del método dependerá de las preferencias del diseñador. En cuanto a las restricciones temporales es posible imponer el retardo máximo admisible entre dos puntos del diseño. Si esta restricción no se cumple el sintetizador puede elegir otra estrategia de síntesis. Por ejemplo para el caso de un sumador se puede optar por sintetizarlo con acarreo paralelo frente a una implementación con acarreo serie. Al igual que en el caso de las restricciones topológicas, las restricciones temporales también se pueden fijar durante la implementación. Sin embargo en este caso es deseable hacerlo durante la síntesis ya que estás pueden determinar la lógica inferida, de forma que si ésta no es óptima los esfuerzos realizados por las herramientas de implementación para buscar el emplazamiento más adecuado de los CLBs pueden resultar vanos. Las restricciones temporales pueden ser globales o individuales. Las primeras se aplican a la totalidad del diseño, siendo éstas las más fáciles de utilizar. Tal y como muestra la figura 1.34 existen cuatro tipos de restricciones globales. Para fijar estas restricciones Leonardo define cuatro variables internas. Estas son: ! ! ! ! input2reg. Indica el máximo retardo admisible entre los puertos de entrada y el primer registro del diseño. En este tiempo se incluye el tiempo de set-up de los biestables. register2register. Indica el máximo retardo admisible entre los dos registros del diseño. En este tiempo se incluye el tiempo de propagación de los biestables del registro de salida y el de set-up de los de entrada. register2output. Indica el máximo retardo admisible entre los registros y los puertos de entrada. En este tiempo se incluye el tiempo de propagación de los biestables del registro de salida. input2output. Indica el máximo retardo admisible entre los dos puertos conectados únicamente por lógica combinacional. -49- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. input2register Bloque combinacional data_in register2register D Q A Bloque combinacional B register2output D Q Bloque combinacional data_out C FF1 FF2 clk clk clock Bloque combinacional D data_in data_out output2output Figura 34: Uso de restricciones temporales globales. Para fijar estas restricciones se emplea el comando set <variable> <valor> donde <valor> es el tiempo de retardo máximo expresado en ns. Así por ejemplo para garantizar que nuestro diseño pueda funcionar al menos a una frecuencia de 10 MHz (T= 100 ns) se emplearían los siguientes comandos: set set set set register2register 100 input2register 100 register2output 100 input2output 100 El otro tipo de restricciones permite fijar individualmente a cada uno de los puertos el máximo retardo admisible. A este tipo de restricciones se les denomina restricciones de puertos y se suelen emplear para optimizar aquellas señales de temporización más crítica. El sintetizador impone una serie de limitaciones a la hora de fijar las restricciones de puertos. Concretamente en el análisis temporal no se toman en consideración los caminos de señal que afectan a las señales de inicialización asíncrona (reset y preset) de los biestables. Tampoco se permite fijar restricciones temporales en diseños con varios relojes asíncronos. Sin embargo, si es posible el análisis de diseños con varios relojes síncronos (diseños multifase). Aun así la variedad de situaciones que se pueden abordar con las restricciones es muy amplia por lo que nos limitaremos a exponer aquellas que aparecen en diseños síncronos con una única señal de reloj. La figura 1.35 ilustra el uso de las restricciones individuales. A continuación se describirán estas restricciones. -50- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín input_arrival clock_cycle DATA_IN Bloque combinacional Circuito externo virtual D Q D Q A Bloque combinacional Bloque combinacional B required_time D Q Bloque combinacional DATA_OUT C FF1 FF2 clk clk FF DATA_OUT2 clk CLK pulse_cycle pulse_width CLK DATA_IN input_arrival required_time DATA_OUT Figura 35: Modelado de restricciones individuales. ! clock_cycle define el periodo máximo (frecuencia mínima ) admisible de la señal de reloj del bloque. Este periodo vendrá dado por la suma del retardo de la salida de los biestables, el tiempo de propagación de la lógica combinacional y el tiempo de set-up de la entrada de los biestables. ! pulse_width permite modelar el ciclo de trabajo de la señal de reloj. ! arrival_time define la demora respecto al flanco de reloj con que llegan los datos a la entrada del bloque. ! required_time define la demora máxima admisible desde el flanco de reloj hasta que los datos aparecen estables en el puerto de salida. Para fijar estas restricciones se emplean los siguientes comandos: clock_cycle <periodo_reloj> <puerto_señal_reloj> pulse_width <ancho_pulso_reloj> <puerto_señal_reloj> arrival_time <valor_retardo> <lista_puertos_entrada> required_time <tiempo_necesario> <lista_puertos_salida> Los primeros parámetros de estos comandos son valores de tiempo expresados en ns. Las lista de puertos se expresan como una lista de nombres entre llaves separadas por espacios. Como ejemplo se mostrarán los comandos a emplear para el circuito de la figura anterior bajo las siguientes suposiciones: ! ! ! ! ! Frecuencia mínima de funcionamiento: 10 MHz. Ciclo de trabajo de la señal de reloj: 25 % Tiempo de demora máximo de los datos de entrada: 12 ns Máximo retardo admisible en salidas secuenciales: 5 ns Máximo retardo admisible en salidas combinacionales: 10 ns Según esto los comandos a emplear serían: clock_cycle 100 clk pulse_width 25 clk -51- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. arrival_time 12 {DATA_IN} required_time 5 {DATA_OUT} En el modelado de una salida puramente combinacional, como es el caso de la señal DATA_OUT2, el tiempo necesario será la suma de la demora de las entradas más el máximo retardo admisible de estas salidas: required_time 22 {DATA_OUT2} Para acceder a las opciones de optimización desde el interface gráfico se utiliza la pestaña , accediendo a la ventana de restricciones. Para generar las restricciones de cada uno de los elementos antes comentados se actúa sobre las pestañas mostrados en la figura 1.36 que se encuentra en la parte inferior de dicha ventana. Figura 36: Selección de las restricciones para la síntesis 4.2.7. Optimización del diseño. La optimización del diseño se realiza mediante el comando optimize, o con la pestaña . Su sintaxis es: optimize [<design_name>] [-target <technology_name>] [-io_target <technology_name>] [-single_level] [-effort <effort_type>] [-chip]|[-macro] [-area]|[-delay]|[-auto] [-pass <pass_nums>]|[-nopass <pass_nums>] [-hierarchy <auto|preserve|flatten>] El primer parámetro especifica el diseño a optimizar. Si no se especifica, éste corresponde al diseño actual. Ésta suele ser la situación típica, si bien para diseños complejos se pueden optimizar por separado cada uno de los módulos que componen el diseño con objeto de obtener mejores resultados. El parámetro target indica la tecnología destino para la que se va a sintetizar (xisxl para nuestro ejemplo). El parámetro chip indica al optimizador que añada buffers de I/O a los puertos de la entidad de mayor nivel. Los parámetros area y delay indican el factor sobre el que se va a tratar de minimizar (consumo de área o retardos) en el diseño. Estos son mutuamente excluyentes. El parámetro efford fija el tipo de esfuerzo a realizar durante la optimización. Los valores válidos son: ! remap Realiza ciertas optimizaciones locales y a continuación el mapeado tecnológico. ! quick Realiza la optimización de una sola pasada y a continuación el mapeado tecnológico. Normalmente esta es la opción empleada en las primeras fases del diseño. ! standard (valor por defecto). Realiza varias pasadas durante la optimización y a continuación el mapeado tecnológico. Para ello se aplican distintas estrategias de optimización obteniendose mejores -52- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín resultados que en el modo quick pero se consume más tiempo. Suele emplearse para afinar los resultados de la síntesis. El parámetro hierarchy indica si se mantendrá la jerarquía de diseño indicada en el código fuente (preserve) o bien si se aplanará el diseño (flatten). Por defecto la optimización de la síntesis se aplica individualmente a cada uno de los módulos que componen la jerarquía del diseño. Sin embargo los límites jerárquicos impiden o limitan las optimizaciones a realizar por lo que puede ser deseable aplanarla. En ciertas ocasiones puede ser deseable preservarla, por ejemplo, para dar un tratamiento especial a bloques de temporización crítica. En cualquier caso se establece como regla de oro que los bloques jerárquicos no tengan tamaños superiores a 50 K puertas. Según lo expuesto el comando empleado en nuestro diseño para realizar la optimización es: optimize -target xisxl -delay -effort quick -chip -hierarchy preserve 4.2.8. Almacenamiento del diseño. Una vez realizada la optimización, se pueden salvar los resultados de la síntesis para su uso posterior. Como se ha comentado estos consisten en una lista de conexiones en la que aparecen elementos de la tecnología destino y otra información adicional (p.e. restricciones para la herramienta de implementación). Esta lista de conexiones se puede salvar en distintos formatos standard (EDIF, VHDL, XNF, etc), si bien lo más idóneo es emplear el formato propio del sintetizador (XDB). Para salvar el diseño del ejemplo en el fichero crono.xdb se emplea el comando: write -format xdb crono.xdb 4.2.9. Exportación de la lista de conexiones. La última operación a realizar durante la síntesis consiste en exportar los resultados de ésta para que puedan ser empleados en las siguientes fases del flujo de diseño. El formato con que se almacene la lista de conexiones dependerá de la herramienta que la utilice en las siguientes fases del flujo de diseño. Si esta lista de conexiones se utiliza con las herramientas de implementación de Xilinx el formato puede ser EDF o XNF. Por ejemplo si se exporta en formato EDIF el comando a emplear para nuestro ejemplo será: auto_write -format edif ../crono.edf Normalmente el comando auto_write suele ir precedido por el comando lo2up que convierte los nombres de los objetos a mayúsculas. Esto evita problemas de interpretación del contenido de la lista de conexiones. De igual forma cuando se utilizan componentes COREGEN se debe ejecutar con anterioridad el comando: set edif_write_arrays FALSE Esto evita que la lista de conexiones generada haga uso de la notación compacta para la definición de buses que emplea formato EDIF. Puesto que las herramientas de Xilinx no admiten esta posibilidad si se empleará esta notación aparecería un error durante la implementación al intentar enlazar ambas listas de conexiones (la generada por el sintetizador y la correspondiente al componente COREGEN). -53- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. Si por el contrario se desea exportar la lista de conexiones como un fichero VHDL estructural para realizar una simulación post-síntesis preimplementación la secuencia de comandos a emplear será: set vhdl_write_component_package FALSE set vhdl_write_use_packages "library IEEE; use IEE.std_logic_1164.all; library UNISIM; use UNISIM.vcomponents.all;" write -format vhdl ../post-synthesis/crono.vhd La desactivación del atributo vhdl_write_component_package evita que los componentes que aparecen en la lista de conexiones se escriba en un paquete a parte. Mediante el atributo vhdl_write_use_packages se indican la declaración a incluir en cada entidad que aparece en el fichero VHDL generado. Finalmente el comando write salva el fichero VHDL La versión de Leonardo empleada en el laboratorio no realiza correctamente la exportación de la lista de conexiones en formato VHDL para FPGAs de la familia Spartan XL. Para otras familias como Spartan II o Virtex no hay ningún tipo de problemas. Para generar el archivo EDIF para la herramientas de implementación se puede utilizar la ventana de la figura 1.37 . Figura 37: Selección del archivo EDIF de salida. 4.2.10. Uso de ficheros de scripts. Toda esta secuencia de comandos se puede almacenar en un fichero de script para su posterior ejecución permitiendo realizar la síntesis de una sola pasada. Con este ejemplo se proporciona el fichero sintetiza.tcl para tal fín. Para ejecutar este fichero ejecute en el comando: source sintetiza.tcl 4.3. ANÁLISIS DE RESULTADOS. -54- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín Para analizar los resultados obtenidos se pueden generar informes del área consumida o de los retardos del diseño. Para generar un fichero con un informe del área consumida se emplea el comando: report_area informe1.txt -cell_usage -hierarchy -all_leafs Parte del contenido de este fichero se muestra en la figura 1.38. ******************************************************* Cell: CRONO View: RTL Library: work ******************************************************* Number Number Number Number Cell Library BUFGP FDC FDCE FDP GND IBUF LUT1 LUT2 LUT3 LUT4 MUXF5 OBUF PRESCALER PULLUP xis2 xis2 xis2 xis2 xis2 xis2 xis2 xis2 xis2 xis2 xis2 xis2 work xis2 of of of of ports : nets : instances : references to this view : Total accumulated area : Number of BUFGP : Number of Dffs or Latches : Number of Function Generators : Number of GND : Number of IBUF : Number of MUXF5 : Number of OBUF : Black Box PRESCALER : Number of PULLUP : Number of gates : References 1 3 16 1 1 2 3 1 5 20 1 14 1 2 x x x x x x x x x x x x x x Total Area 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 16 1 1 2 3 1 5 20 1 14 1 2 BUFGP Dffs or Latches Dffs or Latches Dffs or Latches GND IBUF Function Generators Function Generators Function Generators Function Generators MUXF5 OBUF PRESCALER PULLUP 17 72 71 0 1 20 29 1 2 1 14 1 2 26 *********************************************** Device Utilization for 2s50tq144 *********************************************** Resource Used Avail Utilization ----------------------------------------------IOs 17 92 18.48% Function Generators 29 1536 1.89% CLB Slices 15 768 1.95% Dffs or Latches 20 2082 0.96% ----------------------------------------------- Figura 38: Informe de consumo de área (fichero informe1.txt). De forma similar para generar un informe de las temporizaciones del diseño se emplea el comando: report_delay informe2.txt -num_paths 1 -critical_paths -clock_frequency La figura 1.39 muestra parte del contenido de este fichero. -55- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. Clock Frequency Report Clock : Frequency -----------------------------------CLK : 161.3 MHz Critical Path Report Critical path #1, (path slack = 10.0): NAME GATE ARRIVAL LOAD ---------------------------------------------------------------------------------------CLK/ 0.00 0.00 up 1.90 CLK_IBUF/O BUFGP 0.09 0.09 up 3.70 REG_UNIDADES(2)/C FDCE 0.00 0.09 up 0.00 data arrival time 0.09 data required time (default specified - setup time) 10.09 ---------------------------------------------------------------------------------------data required time 10.09 data arrival time 0.09 ---------slack 10.00 ---------------------------------------------------------------------------------------- Figura 39: Informe de retardos (fichero informe2.txt) Para acceder a las opciones de generación de archivos de informes desde el interface gráfico se utiliza la pestaña , accediendo a la ventana de informes, en la que se puede seleccionar la generación de un informe de área y/o velocidad. Otra forma de analizar los resultados de la síntesis consiste en emplear un método gráfico que permite visualizar en forma de esquemas los módulos inferidos durante la síntesis. Para ello seleccione la opción Tools º Design Browser de la barra de menús, o con el icono . En ese momento se muestra la pantalla que aparece en la figura 1.40. En la parte izquierda de esta ventana se muestra la jerarquía del diseño sintetizado, donde se pueden distinguir claramente las distintas librerías citadas con anterioridad. Navegando por este árbol se puede seleccionar el elemento para el cual se desean mostrar su implementación. Figura 40: Ventana del navegador de diseños. Estos esquemas se pueden mostrar a nivel RTL o a nivel de puertas. En el primer caso los componentes que aparecen son las primitivas genéricas empleadas por el sintetizador durante la síntesis. En el segundo caso los componentes empleados son elementos de la tecnología destino para la que se ha sintetizado. Está claro que los esquemas a nivel de puertas no se pueden visualizar hasta que no se haya completado la fase de mapeado tecnológico. -56- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín Como se puede apreciar, en la ventana del navegador del diseño se muestran dos arquitecturas para la entidad de mayor jerarquía. La primera de ellas tiene el nombre empleado en el código fuente VHDL. Al seleccionar los elementos que aparecen en esta arquitectura se muestran los esquemas RTL. La otra arquitectura tiene el mismo nombre con el sufijo _XRTL correspondiendo a la arquitectura generada tras el mapeado tecnológico. Al seleccionar los elementos que aparecen en esta arquitectura se muestran los esquemas a nivel de puertas. En cualquier caso se puede visualizar uno u otro tipo de esquemas mediante las opciones Tools º View RTL Schematic y Tools º View Gate Level Schematic de la barra de menús, icono . También es posible visualizar el camino de máximo retardo pulsando sobre el botón de la barra de herramientas. En ese momento aparece la pantalla que se muestra en la figura 1.41. Figura 41: Ventana de camino crítico. 5. IMPLEMENTACIÓN DEL DISEÑO. La siguiente fase del proceso de diseño es la implementación de éste empleando para ello las herramientas de Xilinx. Estas herramientas reciben la lista de conexiones en formato EDIF generada durante la síntesis. Para compilar el diseño sintetizado ejecute la herramienta Design Manager seleccionando Inicio º Programas º XilinxISE41 ºAccesories º . A continuación se debe crear un nuevo proyecto seleccionando la opción File º New Project de la barra de menús ( ). En el campo imput design se debe seleccionar el archivo EDIF creado por la herramienta de síntesis, tal y como se muestra en la figura 1.42. -57- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. Figura 42: Creación de un proyecto con el Disign Manager. Al pulsar la pestaña OK se va a crear un subdirectorio xproj en el que se van a almacenar los archivos generados durante la implementación y aparece la ventana de la figura 1.43., que entre otras cosas permite seleccionar el dispositiva sobre el que se va a realizar la implementación. Figura 43: Selección del dispositivo. En un proyecto pueden existir varias versiones y dentro de cada una de ellas, varias revisiones. Una versión corresponde a la compilación del diseño en el que se han producido variaciones en el archivo fuente o se ha seleccionado una nueva familia de dispositivo. Por su parte el término revisión se corresponde con una compilación del diseño en la que se han variado algunos parámetros u opciones de la misma, pero no el archivo fuente. Antes de proceder a la implementación hay que seleccionar las opciones de la misma, para ello se seleccionando Design º Options de la barra de menús. Con el icono , también se puede acceder a las opciones de implementación, Estas opciones se dividen en tres campos (figura 1.44 ): Implementation que permite imponer restricciones para la implementación, Simulation que permite seleccionar el formato del archivo de salida para realizar la simulación temporal o post-implementación y Configuration que permite seleccionar opciones concernientes a la fase de configuración del dispositivo. Para el -58- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín diseño que nos trata sólo se va a retocar el campo de Simulation para indicar que se genere un archivo un archivo VHDL para ser simulado con ModelSim. Figura 44: Opciones de implementación. Con ésto, a parte del fichero de configuración (crono.bit), se generan los ficheros time_sim.vhd y time_sim.sdf empleados para realizar unas simulación VHDL post-implementación (también denominada simulación a nivel de puertas). El fichero time_sim.vhd contiene una descripción estructural de la entidad de jerarquía superior (crono). En este fichero, las herramientas de Xilinx asignan siempre el nombre STRUCTURE a la arquitectura de la entidad de jerarquía superior. Por su parte, el archivo time_sim.sdf contiene la información temporal con los retardos que sufren las señales, presentes en el archivo time_sim.vhd, dentro del dispositivo. Ha de tenerse en cuenta que para que la compilación del diseño se realice correctamente el fichero de lista de conexiones asociado al módulo COREGEN (prescaler.edn) debe encontrarse en el directorio donde ha sido almacenada la lista de conexiones generada por el sintetizador. Antes de proceder con la implementación se puede generar un archivo de restricciones de usuario pueden emplearse para fijar restricciones durante el proceso de implementación del diseño. Con estas restricciones se puede asignar las señales correspondientes a los puertos de la entidad de mayor jerarquía a sus terminales correspondientes, así como otras configuraciones de entrada/salida (slew-rate, estándar lógico, etc) (restricciones topológicas) o bien imponer retardos máximos en los caminos de señal. El fichero de restricciones de usuario (User Constrains File- ucf) se crea con Tools º Constrains Editor , o con , accediendo a la ventana de la figura 1.45. -59- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. Figura 45: Creación de un archivo de restricciones. Con los elementos (crear nuevo archivo ucf) , (abrir archivo ucf) y (guardar archivo ucf)se puede seleccionar el contenido del archivo de restricciones. En la figura 1.46. se muestra el contenido del archivo ucf utilizado en el diseño del tutorial. NET NET NET NET NET NET NET NET NET NET NET NET NET NET NET NET NET "CLK" LOC = "p55"; "DISPLAYDECENAS(0)" LOC = "p4"; "DISPLAYDECENAS(1)" LOC = "p5"; "DISPLAYDECENAS(2)" LOC = "p6"; "DISPLAYDECENAS(3)" LOC = "p7"; "DISPLAYDECENAS(4)" LOC = "p8"; "DISPLAYDECENAS(5)" LOC = "p10"; "DISPLAYDECENAS(6)" LOC = "p11"; "DISPLAYUNIDADES(0)" LOC = "p12"; "DISPLAYUNIDADES(1)" LOC = "p13"; "DISPLAYUNIDADES(2)" LOC = "p14"; "DISPLAYUNIDADES(3)" LOC = "p15"; "DISPLAYUNIDADES(4)" LOC = "p18"; "DISPLAYUNIDADES(5)" LOC = "p20"; "DISPLAYUNIDADES(6)" LOC = "p21"; "LAPSO" LOC = "p22"; "RST" LOC = "p23"; Figura 46: Fichero de restricciones crono.ucf. Una vez creado o seleccionado el archivo de restricciones, se procede a la implementación del diseño, para ello se ejecuta Tools º Flor Engine, o se actúa sobre el botón de la barra de herramientas, creandose de forma automática una nueva versión o revisión según sea el caso. Cuando se ejecuta dicho comando aparece el cuadro de diálogo de la figura 1.47. -60- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín Figura 47: Implementación de un diseño. Los Indicadores de Proceso que posee la ventana de la figura anterior muestran en qué etapa se encuentra el flujo del diseño en ese preciso momento. Las flechas entre cada paso se vuelven de color negro después que el paso previo ha terminado. En la barra de proceso que muestra el estado en que se encuentra cada proceso, ya sea en ejecución (Running), completado (Completed), abortado (Aborted) o con algún error en la ejecución (Failed). Para el caso de trabajar con FPGA’s, los procesos son: - Translate: Realizar la traducción del diseño. - Map: Realizar la partición del diseño. - Place&Rute: Realizar el emplazamiento y ruteado del diseño. - Timing(Sim). Genera un archivo de retardos paar realizar simulación temporal - Configure: Genera el archivo de configuración. una El proceso de implementación de un diseño conlleva la ejecución secuencial de una serie de herramientas, cada una de las cuales genera un archivo ASCII de informes (reporters) en el que se reflejan todas las acciones realizadas por el mismo, así como los errores o avisos (warnings) que se producen. En la figura 1.48. se muestra el grupo de archivos de informes generados durante la implementación de un diseño para una FPGA. Para acceder a la los informes de la barra de ejecuta Utilies º Report Browser, o se actúa sobre el botón herramientas, Figura 48: Archivos de informes de la implementación 6. SIMULACIÓN A NIVEL DE PUERTAS. -61- Ingeniería Electrónica. Laboratorio de Diseño de Circuitos y Sistemas Electrónicos. El proceso a seguir para llevar a cabo la simulación post-implementación es muy similar al descrito para la simulación RTL variando únicamente los ficheros VHDL a emplear en cada caso. El archivo a compilar es ahora el time_sim.vhd, el cual contiene una descripción estructural realizad con componentes de la tecnología destino. Una vez compilado se crea la arquitectura structure para el componente crono, por lo que habrá que crear una nueva configuración para seleccionar el uso de dicha arquitectura en el testbench. El fichero que contiene la configuración para la simulación temporal es cnf_temporal.vhd. Así la secuencia de comandos a ejecutar será: vcom -87 time_sim.vhd vcom -93 testbench.vhd vcom -93 cnf_temporal.vhd Los comandos para realizar la compilación de los archivos necesarios para realizar la simulación temporal se encuentran en el scrip compila_tmp.do. En una simulación temporal a la hora de cargar el diseño a simular es preciso indicar la entidad sobre la que se aplicará el fichero .sdf que contiene las retroanotaciones de retardos. La sintaxis empleada para ello por el comando vsim es: vsim [-sdfmin | -sdftyp | -sdfmax [<instance>=]<sdf_filename>] [<library_name>.<design_unit>] Según esto para nuestro caso mediante la opción -sdfmax se empleará el valor máximo de los retardos retroanotados (simulación del peor caso). Estos se aplicaran al componente uut que está instanciado en la raíz (“/”) de la jerarquía. Estos retardos se encuentran almacenados en el fichero time_sim.sdf. Con esto el comando a emplear sería: vsim -sdfmax /dut=../time_sim.sdf cnf_temporal vsim -sdfmax dut=C:/tutorial/time_sim.sdf work.cnf_temporal -multisource_delay Desde el interface gráfico, una vez actuado sobre latest y seleccionada la unidad de diseño a simular (cnf_temporal) con la pestaña SDF se selecciona el archivo que contiene la información temporal haciendo uso de la ventana de la figura 1.49. Figura 49: Selección del archivo sdf. -62- Diseño en VHDL para FPGAs. R. Mateos, I. Fernández. P. Martín En la figura anterior actúando sobre la pestaña add se selecciona el archivo sdf y el elemento sobre el que se aplica (figura 1.50 ), para ello se indica la referencia que el componente tiene en el testbenc (dut). Figura 50: Parámetros del archivo sdf. El resto de comandos a emplear son exactamente los mismos, salvo por un pequeño detalle. Durante el proceso de síntesis y su posterior implementación puede ocurrir que determinadas señales internas desaparezcan debido a optimizaciones realizadas por estas herramientas. Por tanto es aconsejable visualizar únicamente los puertos de la entidad del diseño, nunca señales internas. Tan sólo en el caso de que por motivos de depuración fuese necesario visualizar señales internas únicamente es posible visualizar los puertos de los componentes instanciados en el código VHDL y siempre que se preserve la jerarquía durante la síntesis. Con esto los comandos necesarios para seleccionar las señales a visualizar serán: # Definicion de se¤ales a visualizar. add add add add add add add add add add wave wave wave wave wave wave wave wave wave wave /testbench/rst_tb /testbench/clk_tb /testbench/dut/en1hz /testbench/lapso_tb /testbench/dut/state /testbench/dut/actualizar -unsigned /testbench/dut/cntunidades -unsigned /testbench/dut/cntdecenas /testbench/displayunidades_tb /testbench/displaydecenas_tb run 400 ns force -freeze testbench/dut/EN1HZ 1 run 50 us Estos comandos están recogidos en el script sim_temporal.do -63-