DISEÑO EN VHDL PARA FPGAs de
XILINX
SIMULACIÓN FUNCIONAL
Versión 1.0
Dr. Ignacio Bravo Muñoz
Dr. Alfredo Gardel Vicente
ENERO 2010
DPTO. ELECTRONICA – UNIVERSIDAD DE ALCALA
INDICE:
4 SIMULACIÓN FUNCIONAL DEL DISEÑO ... 2
4.1 INTRODUCCIÓN... 2
4.2 MANEJO DEL SIMULADOR ... 6
4.3 PUNTOS DE RUPTURA... 23
4 SIMULACIÓN FUNCIONAL DEL DISEÑO
4.1 INTRODUCCIÓN
Para verificar la validez del diseño realizado se realizará una simulación de funcional (también denominada de comportamiento o a nivel RTL) empleando para ello el simulador ModelSim de Mentor Graphics. Para ello ejecute el simulador seleccionando
Inicio => Programas => ModelSim SE 6.0 => ModelSim
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.
La secuencia de comandos a emplear para realizar una simulación se puede 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 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.
4.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.
El simulador ModelSim 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 (se crea junto con el proyecto *.mpf).
Las librerías de recursos contienen unidades de diseño a las que se puede hacer referencia desde un 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 DCM 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 proyecto actual.
Una vez creada la librería se puede 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. Recuérdese 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 dentro de la sentencia vcom. 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 poder referenciarlas.
• 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 esté 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 Xilinxcorelib 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>
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 ningún tipo de modificaciones sobre ellas.
Teniendo en cuenta lo expuesto, y 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 la instalación de ISE. Busque un directorio con 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.
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 $unisim/unisim_VPKG.vhd vcom work unisim $unisim/unisim_VCOMP.vhd vcom work unisim $unisim/unisim_VITAL.vhd vmap unisim c:/VHDL_Xilinx_lib/unisim • Compilación de la librería simprim.
vlib Simprim
vcom work simprim $simprim/simprim_Vpackage.vhd vcom work simprim $simprim/simprim_Vcomponents.vhd vcom work simprim $simprim/simprim_VITAL.vhd vmap simprim c:/VHDL_Xilinx_lib/simprim • Compilación de la librería XilinxCoreLib.
vlib XilinxCoreLib
vcom work XilinxCoreLib $XilinxCoreLib/mvlutil.vhd vcom work XilinxCoreLib $XilinxCoreLib/mvlarith.vhd vcom work XilinxCoreLib $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 en ModelSim:
source xilinx_lib.tcl
Otra forma de compilar las librerías, es usar el compilador de librerías proporcionado por Xilinx. Para lo cual tendríamos que realizar lo siguiente:
cd $ISE\bin\nt
compxlib -s mti_se -p $ModelSim\win32 -f all:u -l vhdl -o C:\xilinx_libs\ compxlib -s mti_se -p $ModelSim\win32 -f all:s -l vhdl –o C:\xilinx_libs\ compxlib -s mti_se -p $ModelSim\win32 -f all:c -l vhdl -o C:\xilinx_libs\
Y tras haber sido compiladas realizar desde Modelsim el mapeado de las mismas, de la siguiente forma:
ModelSim> vmap Unisim C:/xilinx_libs/Unisim ModelSim> vmap Simprim C:/xilinx_libs/Simprim
ModelSim> vmap XilinxCoreLib C:/xilinx_libs/XilinxCoreLib
La creación de estas librerías sólo se debe realizar una vez, es decir, no es preciso compilar estas librerías para cada nuevo diseño a realizar, sólo mapearlas. Se puede incluir bien en el proyecto de cada diseño o bien en el propio entorno de ModelSim modificando apropiadamente el archivo de inicialización modelsim.ini de forma que dichas librerías serán siempre visibles para posteriores diseños.
··· unisim = $MODEL_TECH/../unisim cpld = $MODEL_TECH/../cpld simprim = $MODEL_TECH/../simprim xilinxcorelib = $MODEL_TECH/../XilinxCoreLib ···
4.2 MANEJO DEL SIMULADOR
Veamos ahora cada uno de los pasos que se deben realizar para lograr una simulación funcional de nuestro diseño:
1. Creación del proyecto.
2. Creación de nuevas librerías y mapeado de las librerías a reutilizar. 3. Compilación del código fuente.
4. Carga de la unidad de diseño a simular. 5. Definición de puntos de prueba.
6. Avance y detención de la simulación. 7. Introducción de estímulos.
8. Análisis de resultados.
9. Finalización de la sesión de simulación.
4.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 siguiente.
Figura 1. Creación de un proyecto de ModelSim
Con los datos de creación de este nuevo proyecto se creará automáticamente el subdirectorio behavioral dentro del directorio c:\tutorial. Además ModelSim crea automáticamente la librería work definiéndola como la librería de trabajo para este nuevo diseño. Por tanto, el path de esta librería será c:/tutorial/behavioral/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
los cuales pueden introducirse en un fichero do.
4.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. 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 $Xilinx_lib/unisim vmap simprim $Xilinx_lib/simprim vmap XilinCoreLib $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 puede considerar 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. Otra forma sencilla de verificar si las librerías son visibles para el proyecto actual es mediante la opción View => Workspace (en versiones anteriores Design => Browse Libraries) de la barra de menús tal y como muestra la figura siguiente. En caso de que no aparezcan las librerías citadas será preciso realizar el mapeado de éstas.
Figura 2. Listado de las librerías de componentes mapeadas
4.2.3 Compilación del código fuente.
Una vez creado el proyecto (en la carpeta funcional) 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 de dicho directorio funcional. Si un fichero VHDL proporciona una unidad de diseño que será instanciada en otro fichero se debe seguir dicho orden jerárquico en la compilación. Para compilar los ficheros fuente del diseño se han de ejecutar los siguientes comandos desde la consola de ModelSim:
#Script de compilacion. vcom -93 {../bcd2seg.vhd} vcom -93 {../mux_displays.vhd} vcom -93 {../maq_FSM.vhd} vcom -93 {../regs_FSM.vhd} vcom -93 {../Core_Contador/prescaler.vhd} vcom -93 {../Prueba_DCM.vhd} vcom -93 {../crono.vhd} vcom -93 {../crono_tb.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 la 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 siguiente aparece un ejemplo de ello.
Figura 3. Ejemplo de un error en compilación y visualización de la línea de código erronea.
4.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 el siguiente:
vsim [ lib <nombre_librería>]
[ t [múltiplo]<unidades_tiempo>]
[ 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 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.rtl
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 siguiente. Adicionalmente puede emplearse un factor multiplicador siendo los valores admisibles 1, 10 o 100. Si no indica la resolución, por defecto el simulador usa una resolución de 1 ns.
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. Nótese 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, empleándose para especificar el fichero sdf que contiene la retroanotación de retardos y qué caso de retardo elegir (xxx=min avg max). Por este motivo su explicación detallada se verá en el apartado destinado a la simulación temporal.
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 entidad crono, por lo que el comando a emplear será:
vsim crono
4.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 (signal) 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 y como muestra la figura siguiente el simulador define un total de ocho ventanas destinadas a representar los distintos tipos de elementos.
Figura 4. Diferentes ventanas del simulador.
Veamos la función de cada una de estas ventanas:
• 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:
view *
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 structure y signal. 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 siguiente 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 5. Vista de la estructura del diseño y sus señales correspondientes
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 siguiente.
Figura 6. Ventana de formas de onda de las señales seleccionadas
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 p.e. wave.do para así poder volverlo a utilizar en posteriores sesiones de simulación (también en 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 los vectores se representen en formato numérico. Las tres últimas opciones permiten 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ñales. La figura siguiente muestra un ejemplo de ello.
Figura 7. Ejemplo de tratamiento digital de señales vistas en la ventana de formas de onda
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 (clk_fpga y EN1HZ) y el estado de la presentación dado por la 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:
# Definicion de señales a visualizar.
add wave /crono_tb/pepito/lapso add wave /crono_tb/pepito/rst add wave /crono_tb/pepito/clk
add wave /crono_tb/pepito/sel_display add wave /crono_tb/pepito/seg7_code add wave /crono_tb/pepito/clk_fpga add wave /crono_tb/pepito/en1khz add wave /crono_tb/pepito/en1hz add wave /crono_tb/pepito/dec_cnt
add wave -unsigned /crono_tb/pepito/cntunidades add wave -unsigned /crono_tb/pepito/cntdecenas #add wave /crono_tb/pepito/rst_n
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 visualizar, y se añaden al archivo script de 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.
Los comandos utilizados para cargar el diseño a simular y configurar la ventana de formas de onda se recogen en el script simula.do proporcionado en el directorio funcional.
4.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 dada anteriormente. 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.
Según esto el comando:
run -all
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 siguiente. En ella se puede seleccionar qué elementos mantendrán la configuración fijada durante la sesión de simulación actual.
Figura 8. Pantalla que pregunta acerca de qué elementos se desea reiniciar
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 cargar de nuevo tal y como se ha descrito anteriormente.
4.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 testbench. 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:
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 señal 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 force con el periodo de tiempo especificado.
cancel <tiempo> Cancela el force una vez transcurrido el tiempo especificado.
A continuación se muestran varios ejemplos del uso de este comando.
Sentencia Funcionamiento
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 wave /prescaler/aclr add wave /prescaler/clk add wave /prescaler/q add wave /prescaler/thresh0
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 /crono_tb/pepito/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 /crono_tb/pepito/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.
# script de simulacion
# Definicion de señales a visualizar.
vsim crono_tb -t 100ps
# Definicion de señales a visualizar.
add wave /crono_tb/pepito/lapso add wave /crono_tb/pepito/rst add wave /crono_tb/pepito/clk
add wave /crono_tb/pepito/sel_display add wave /crono_tb/pepito/seg7_code add wave /crono_tb/pepito/clk_fpga add wave /crono_tb/pepito/en1khz add wave /crono_tb/pepito/en1hz add wave /crono_tb/pepito/dec_cnt
add wave -unsigned /crono_tb/pepito/cntunidades add wave -unsigned /crono_tb/pepito/cntdecenas #add wave /crono_tb/pepito/rst_n
#Durante este tiempo se esta ejecutando el reset impuesto desde el testbench
force -freeze /crono_tb/pepito/en1khz 1 0 , 0 200 ns -r 400 ns
run 1ms
Para realizar la simulación funcional del diseño se debe ejecutar el comando: do simula.do
La figura siguiente 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 9. Formas de onda de las señales del diseño bajo test (pepito)
4.2.8 Análisis de resultados.
En este apartado se comentará cómo 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 para realizar el Zoom de acercamiento/Zoom de alejamiento, ampliar una zona de los cronogramas al tamaño horizontal del rectángulo o mostrar en la pantalla el ancho total de la simulación realizada. 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 siguiente, é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 realizar distintas medidas de tiempos entre flancos de las señales.
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 10. Ejemplo de medición de tiempos entre cursores dentro de la ventana de ondas (wave)
4.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 siguiente: quit –sim
o bien:
Figura 11. Finalización de la Simulación de la ventana Wave.
Nótese 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 un 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 banco 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 fichero 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 finaliza la sesión de simulación. En ese momento el fichero de salida puede abrirse con otra herramienta.
4.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 se desea poner el punto de ruptura. Para desactivarlo basta con una nueva pulsación. Cuando se ejecuta la línea de código marcada la simulación se detiene.
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, desde la ventana de comandos, 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.
Expresión. Ejemplo
Igualdad. clk = ’1' ó clk==’1' Desigualdad bus1 /= “0000" Detección de eventos: clk’EVENT
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 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
De esta 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
4.4 METODOLOGÍA DE TRABAJO.
En la descripción realizada a cerca del manejo del simulador se ha hecho especial hincapié en su uso mediante comandos, obviándose 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, para después simular y observar los resultados. Mediante el uso de ficheros scripts esto se reduce a seleccionar mediante 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 múltiples veces. Además los scripts creados para la simulación funcional se usan 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.
Merece la pena hacer hincapié 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.