DISEÑO EN VHDL PARA
FPGAs
Raúl Mateos Gil.
Ignacio Fernández Lorenzo.
Pedro Martín Sánchez.
ÍNDICE
1. FLUJO DE DISEÑO VHDL SOBRE FPGAs. . . . 1
1.1.INTRODUCCIÓN. . . . 1
1.2. STANDARDVITAL . . . 1
1.3.CREACIÓNDELMODELO. . . . 2
1.4. SÍNTESISDELMODELO.. . . 3
1.5. IMPLEMENTACIÓNDELMODELO. . . . 4
2. DESCRIPCIÓN DEL DISEÑO A REALIZAR. . . . 5
2.1.CREACIÓNDELMÓDULOLOGIBLOX. . . . 8
2.2.MÓDULOBCD2SEG. . . . 10
2.3.MÓDULOCRONO.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.BANCODEPRUEBAS. . . . 17
2.5.FICHEROCONFBEHAVIORAL.VHD . . . 19
3. SIMULACIÓN FUNCIONAL DEL DISEÑO. . . . 20
3.1.INTRODUCCIÓN. . . . 20
3.1.1. Librerías.. . . 21
3.2.MANEJODELSIMULADOR. . . . 23
3.2.1. Creación del proyecto. . . . 24
3.2.2. Creación de nuevas librerías y mapeado de las librerías a reutilizar . 24 3.2.3. Compilación del código fuente. . . . 25
3.2.4. Carga de la unidad de diseño a simular . . . 26
3.2.5. Selección de puntos de prueba. . . . 27
3.2.6. Avance y detención de la simulación. . . . 31
3.2.7. Introducción de estímulos. . . . 33
3.2.8. Análisis de resultados. . . . 35
3.2.9. Finalizar una sesión de simulación. . . . 36
3.3.PUNTOSDERUPTURA.. . . 36
3.4.METODOLOGÍADETRABAJO. . . . 38
4. SÍNTESIS DEL DISEÑO. . . . 39
4.1.OPERACIÓNINTERNADELSINTETIZADOR. . . . 39
4.1.1. Generadores de módulos. . . . 42
4.2.MANEJODELSINTETIZADOR. . . . 43
4.2.1. Inicialización del sintetizador. . . . 45
4.2.2. Selección de la tecnología destino. . . . 45
4.2.3. Selección del método de codificación de las máquinas de estados. . . 45
4.2.4. Lectura de ficheros del diseño. . . . 47
4.2.5. Selección del diseño actual. . . . 47
4.2.6. Configuración de opciones de optimización. . . . 48
4.2.7. Optimización del diseño. . . . 51
4.2.9. Exportación de la lista de conexiones. . . . 52
4.2.10. Uso de ficheros de scripts.. . . 53
4.3.ANÁLISISDERESULTADOS. . . . 53
5. IMPLEMENTACIÓN DEL DISEÑO. . . . 55
5.1.USODEFICHEROSDERESTRICCIONES. . . . 57
Editor VHDL
HERRAMIENTAS DE IMPLEMENTACIÓN
El diseño contiene componentes LogiBLOX instanciados LogiBLOX .NGC XNF EDIF Fichero fuente RTL VHDL SINTETIZADOR VHDL SIMULADOR VHDL VHDL VHDL BIT JEDEC EDIF VHDL SDF VHI Plantillas de instantación Modelo de simulación del componente LogiBLOX. Fichero de lista de conexiones de salida. LIsta de conexiones en formato nativo. Simulación RTL. Simulación post-sintesis pre-implementación. Fichero de programación
del dispositivo. Ficheros de lista de conexiones para simulación post-implementación
Ficheros de informes VITAL Comportamiento VITAL Banco de pruebas VHDL Restricciones . de diseño Fichero de restricciones de usuario. UNISIM LogiBLOX SIMPRIM SI M U L ACI Ó N FU NCI O N A L . S IM U L ACI ÓN T E M P ORAL.
Figura 1: Flujo de diseño en VHDL para FPGAs de Xilinx.
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 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
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
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.
Lista de conexiones de entrada .XNF o EDIF
HERRAMIENTAS
FASES
.NGD NGDBUILDDiseño jerárquico aplanado
TRCE
Estimación de retardos estáticos.
TRCE
Estimación de retardos estáticos. NGDANNO & NGD2VHDLRetroanotación de retardos.
Generación de ficheros simulación temporal VHDL . PAR
Emplazamiento del diseño físico Interconexión del diseño físico.
MAP Traducción lógica a física. Agrupamiento de LUTs y FFs en CLBs
.NCD
.NCD
.PCF
BITGEN
Obtención del fichero de configuración.
.BIT
VHDL SDF
Figura 2: Flujo de implementación.
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.
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
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.
MARCHA
DisplayUnidades
DisplayDecenas
FPGA
Vcc R R MARCHA UPDOWNrst
lapso
RST
Vcc
P1
OSCILADORclk
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. BCD2SEG BCD2SEG CONTADOR 0-59 PRESCALER prescaler.vhd crono.vhd lapso bcd2seg.vhd REGISTROS FSM EN EN EN1HZ DIVISOR 1 / 10E10 clk rst
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
P=1 P=0 P=1 P=1 P=1 P=0 P=0 P=0 S3 0 S2 0 S4 1 S1 1
Figura 5: Grafo de la máquina de estados.
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.
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.
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.
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
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(98967F
H ) 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".
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 std_logic_vector(3 downto 0); -- input data
Display:out std_logic_vector(6 downto 0));
end BCD2SEG;
architecture inside of BCD2SEG is begin with BCD select Display <= "0111111" when "0000", --0 "0000110" when "0001", --1 "1011011" when "0010", --2 "1001111" when "0011", --3 "1100110" when "0100", --4 "1101101" when "0101", --5 "1111101" when "0110", --6 "0000111" when "0111", --7 "1111111" when "1000", --8 "1100111" when "1001", --9 "0000000" when others; --0 end inside;
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: 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));
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: std_logic_vector(3 downto 0);
signal Decenas: std_logic_vector(3 downto 0);
signal CntUnidades: unsigned(3 downto 0);
signal CntDecenas: unsigned(3 downto 0);
signal EN1HZ,rst_n: std_logic;
-- Estados de la FSM que controla el sistema. type stateFSM is (
S1, -- RunningWaitingOnPush S2, -- RunningWaitingOnRelease S3, -- FrozenWaitingOnPush S4); -- FrozenWaitingOnRelease signal state: stateFSM;
signal actualizar: std_logic; begin
-- Instantación de los decodificadores BCD a 7 segmentos.
U1 : BCD2SEG port map (
BCD => Unidades,
DISPLAY => DisplayUnidades);
U2 : BCD2SEG port map (
BCD => Decenas,
DISPLAY => 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;
-- 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
Lógica combinacional Proceso síncrono
Proceso combinacional Lógica
secuencial combinacionalLógica
Cálculo del
próximo estado las salidas.Cálculo de
Elementos de memoria
Entradas (sólo para tipo Mealy) Entradas asíncronas Reloj Próximo estado Estado actual Entradas Salidas
Figura 11: Estructura de una máquina de estados.
else CntDecenas <= CntDecenas + 1; end if; else CntUnidades <= CntUnidades + 1; end if; end if; end if; end process; 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.
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
type stateFSM is (
S1, -- RunningWaitingOnPush
S2, -- RunningWaitingOnRelease
S3, -- FrozenWaitingOnPush
S4); -- FrozenWaitingOnRelease
signal state: stateFSM;
signal actualizar: 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.
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;
-- 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);
begin
-- 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.
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
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
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:
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_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 simprim
vcom -work simprim C:/ise41/vhdl/src/simprims/simprim_Vpackage.vhd vcom -work simprim C:/ise41/vhdl/src/simprims/simprim_Vcomponents.vhd vcom -work simprim C:/ise41/vhdl/src/simprims/simprim_VITAL.vhd vmap 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.
Figura 14: Ventana de creación de proyecto.
Û 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.
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
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.
Figura 16: Visualización automática de errores en el código fuente.
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 -93 bcd2seg.vhd vcom -93 prescaler.vhd vcom -93 crono.vhd vcom -93 testbench.vhd vcom -93 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.
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>]
[-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.
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
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
Figura 17: Ventanas del simulador.
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
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:
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.
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
Figura 20: Ejemplo de representación analógica de señales.
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.
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 wave /testbench/rst_tb add wave /testbench/clk_tb add wave /testbench/dut/en1hz add wave /testbench/lapso_tb add wave /testbench/dut/state add wave /testbench/dut/actualizar
add wave -unsigned /testbench/dut/cntunidades add wave -unsigned /testbench/dut/cntdecenas add wave /testbench/displayunidades_tb
add wave /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.
add wave -noupdate -format Logic /testbench/rst_tb add wave -noupdate -format Logic /testbench/clk_tb add wave -noupdate -format Logic /testbench/dut/en1hz add wave -noupdate -format Logic /testbench/lapso_tb add wave -noupdate -format Literal /testbench/dut/state add wave -noupdate -format Logic /testbench/dut/actualizar
add wave -noupdate -format Literal -radix unsigned /testbench/dut/cntunidades add wave -noupdate -format Literal -radix unsigned /testbench/dut/cntdecenas add wave -noupdate -format Literal /testbench/displayunidades_tb
add wave -noupdate -format 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