Conjunto de Herramientas para Desarrollo de Hardware con FPGA

Desde HDL hasta una FPGA Operativa


Copyright (C) 2007 Fernando G. Tinetti

La idea de este documento es, justamente, documentar el desarrollo de un dispositivo de hardware desde la especificación en un HDL (Hardware Description Language) hasta la evaluación con la medición de las señales de entrada y salida del dispositivo implementado en FPGA con un analizador lógico.

Para la especificación, simulación, implementación y medición se utilizarán:

Está claro que en este documento se tratan herramientas específicas, pero la idea es que esto no quite la generalidad del "ciclo" (aunque aquí será como una "cascada") de desarrollo de hardware desde la especificación hasta la verificación/evaluación del dispositivo mismo sobre una FPGA. Puesto de otra manera, los pasos de

son, en realidad, generales. Se pueden hacer con el "combo": Verilog-QII-Agilent o, por ejemplo, con VHDL-ISE (de Xilinx)-Osciloscopio de HP. Puesto de otra manera, si bien en este documento se trata un HDL en particular (Verilog), un entorno de desarrollo particular (Quartus II), una FPGA particular (10K10), y una herramienta de medición en particular (analizador lógico), la idea es que el ciclo de desarrollo (o la cascada, que se verá en este caso) se pueda llevar a cabo con las herramientas correspondientes en cada caso: lenguaje de descripción de hardware, software de desarrollo y programación de FPGA y herramienta de medición de dispositivos.

Gran parte de la explicación contenida en esta página puede encontrarse en varios otros sitios, aunque se han utilizado relativamente pocos documentos de referencia que son muy buenos. Sin embargo, se ha hecho un esfuerzo considerable en enfocar la información y la metodología hacia la idea de "comenzar con HDL y terminar midiendo un dispositivo". Dado que hay varias herramientas involucradas, era de esperar que no toda esta información estuviera en un solo documento o en una sola fuente. Más específicamente, el primer documento de descripción de QII utilizado es
"Quartus II Introduction Using Verilog Design", disponible en
http://www.altera.com/education/univ/materials/manual/labs/tut_intro_verilog.pdf 
es decir que es información "oficial" de Altera. Más en general, se puede recurrir a las páginas web de Altera donde se describe la documentación asociada a QII en general y a QII para diseño:
http://www.altera.com/support/software/sof-quartus.html
http://www.altera.com/support/software/quartus2/design_flow/des-index.html

El manual más completo disponible de QII es "Introduction to Quartus II", que está disponible en el sitio web de Altera:
http://www.altera.com/literature/manual/intro_to_quartus2.pdf

Sin lugar a dudas existen otras fuentes de información, la información que se describe y resume aquí incluye partes de los documentos elaborados por el prof. Zvonko George Vranesic
http://www.eecg.toronto.edu/~zvonko/
específicamente, los apéndices B, C y D que están disponibles en su página web (aunque no queda claro a cuál de sus libros corresponden los apéndices)
http://www.eecg.toronto.edu/~zvonko/AppendixB_quartus.pdf
http://www.eecg.toronto.edu/~zvonko/AppendixC_quartus.pdf
http://www.eecg.toronto.edu/~zvonko/AppendixD_quartus.pdf
También hay información disponible de cursos universitrarios sobre FPGA donde utilizan algún producto de Altera y en todos los casos utilizan QII como software de desarrollo.

Diseño en Verilog de un Dispositivo Simple: Un Inversor

A) Todo diseño en QII se crea en el contexto de un proyecto. Para la creación de un proyecto, dentro de QII
      A.1) File -> New Project Wizard
      A.2) En la pantalla del wizard
Click on Next
      A.3) Se abre la siguiente pantalla del wizard con: Directorio, Nombre del proyecto, Entidad de mayor nivel del diseño
            A.3.1) Directorio: recomendado crear un directorio por proyecto, independientemente del que se muestra (que es del propio QII). Ej: c:\users\user1\nombre_proy
            A.3.2) Nombre del proyecto: recomendado que sea el mismo que la entidad de mayor nivel del diseño. Ej: inv (de inversor)
            A.3.3) Entidad de mayor nivel del diseño: inv (será un inversor)
Click on Next
      A.4) Se abre la siguiente pantalla del wizard con la posibilidad de agregar archivos con diseños ya hechos al proyecto
Si hay archivos de éstos, agregarlos
Click on Next
      A.5) Se abre la pantalla del wizard con la selección del hardware a usar (FPGA, etc.)
muestra lo que encuentra (que es correcto): familia FLEX10K, dispositivo disponible EPF10K10... (el mismo de la placa)
Click on Next
      A.6) Se abre la pantalla del wizard con EDA tools
poner las que se usen (ninguna)
Click on Next
      A.7) Se abre la pantalla del wizard con el resumen
Click on Finish
En QII (como resultado de todo lo anterior): Aparece en Entity el nombre de la familia y del dispositivo y en el nivel siguiente el nombre de la entidad de diseño de mayor nivel


B) A partir de este punto se deben incluir especificaciones Verilog en el proyecto. En QII
      B.1) File -> New...
      B.2) Se abre la pantalla del New..., y en ella
Seleccionar Verilog HDL File
En QII (como resultado de lo anterior): aparece en pantalla un editor de textos propio de QII con el nombre de archivo Verilog1.
Para que el nombre del archivo sea el mismo que el de la entidad que se describe, se hace
File -> Save As...
en la pantalla del Save As.. directamente con el nombre de la entidad de diseño de mayor nivel que ya se dio: inv, el archivo se llama, entonces, inv.c (al final de la pantalla aparece que el archivo será incluido en el proyecto actual).
      B.3) En este punto se pone todo lo que sea necesario en el archivo de texto (especificación Verilog). En este caso:

   // FGT May 11th, 2007
   module inv (bin, bout);
     input bin;
     output bout;
     assign bout = ~ bin;
   endmodule
que es simplemente un inversor de la señal de entrada. Guardar el archivo.


C) Una vez que se ha finalizado de incorporar la especificación HDL de los dispositivos del diseño, se debe realizar la Síntesis Funcional y Simulación Funcional. En algunas ocasiones se presenta simplemente como "Síntesis", pero parece apropiado aclarar desde ahora que esta serie de pasos corresponde a la simulación funcional porque:
           1) La primera simulación debería ser funcional para verificar que el diseño hace lo que se pretende que haga desde el punto de vista lógico.
           2) La simulación funcional es la más rápida en tiempo de ejecución. Esto no es significativo para este ejemplo, pero sí lo es cuando el sistema es relativamente complejo.
           3) La simulación funcional no usa ninguna información del hardware a utilizar, en este sentido es "independiente del hardware" con todo lo bueno y malo que esto tiene asociado.
Los pasos a seguir para esta fase son básicamente tres:
           C.1) Análisis compilación del diseño.
           C.2) Generación de los patrones de test.
           C.3) Simulación funcional.
A continuación se muestra cómo se lleva a cabo cada uno de estos pasos con QII.
           C.1) Análisis o compilación del diseño. En QII
Processing -> Start -> Start Analysis & Synthesis (ctrl-k)
termina sin errores o mostrando los errores que correspondan (como cualquier compilador).
Click on OK
          C.2) Generación de los patrones de test. En QII
File -> New...
En la pantalla del New...
Seleccionar la pestaña Other Files
Seleccionar Vector Waveform File
En QII aparece la pantalla del Waveform Editor. Como en el caso del archivo Verilog, guardar este archivo con el nombre de la entidad de diseño de mayor nivel (que es la que se quiere simular con las señales que se están definiendo en este punto).
File -> Save As...
pantalla del Save As...
inv (agrega .vwf y lo incluye al proyecto por default)
En este punto hay que incluir varios datos relacionados con las señales de entrada y con la cantidad de tiempo a simular, aun cuando la simulación sea funcional. Debe recordarse que todo lo relacionado con el hardware se considera "de respuesta instantánea" para la simulación funcional, pero es necesario definir tiempo para asociar los cambios de las señales con una evolución temporal del sistema.
Edit -> End Time
Pantalla: poner 100 ns
Para ver todo el período en la pantalla de QII
View -> Fit in Window

Aprovechando para hacer otra sesión, saliendo y volviendo a entrar a QII.
Salir: File -> Save Project
Cuando se reingresa,
File -> Open Project
Seleccionar el proyecto que se salvó anteriormente (inv)
Todo lo que hace es mostrar que abrió un proyecto. Si se hace doble click en el nombre, que está a la izq., aparece el archivo de texto con Verilog.
Probando seguir a partir de lo que se dejó, es decir en la generación de patrones de test previo a la simulación funcional...
File -> Open...
Aparece por default Device Design Files, pero cambiar a Waveform/Vector Files
Allí aparece el único generado en/para este proyecto, es decir inv.wvf, y al abrirlo tiene todo lo estrictamente relacionado con señales que se haya incluido en el editor de señales. No está, por ejemplo, el "simulation end time". Es más, de alguna manera, el "Simulation end time" se ha perdido, puede ser considerado propio de la sesión y no del proyecto.
Se vuelve a poner el Simulation End Time como se indica en C.2 (100 ns)
El Compilation Report reaparece tal como fue generado en su momento, es decir que sí tiene lo mismo que antes de cerrar el proyecto.

Retomando la generación de señales para la simulación... patrones de test
Para agregar señales/patrones de test en el editor de fromas de onda...
Edit -> Insert -> Insert Node or Bus
Se abre la pantalla de inserción y aquí conviene utilizar el botón de esta pantalla denominado "Node Finder..."
Al usar Node Finder... se abre otra pantalla en la que hay que utilizar el botón "List" para que muestre/despliegue las señales involucradas en las entidades del proyecto
Elegir, en este caso: bin (con doble click ya la "pasa" a "Selected Nodes"), lo mismo para bout. Se debe hacer notar que esta selección genera que la señal correspondiente aparezca luego en la pantalla del editor de señales (en este punto no se le da valor a ninguna señal en ningún instante/intervalo de tiempo).
Al hacer ok en la pantalla anterior aparece bin con estado en 0 y bout mostrando que no tiene valor conocido.
Evidentemente se debe asignar valor/estado a bin, correr la simulación funcional y ver si lo que se genera en bout es correcto.
Para dar valores a bin...
Seleccionar bin (click sobre el nombre de la señal en el editor de señales en el que se está)
Se activan/están disponibles un conjunto de posibilidades en el editor de señales en el medio de la pantalla, entre ellas el que corresponde a "Overwrite Clock", que es el único botón que incluye un reloj en su dibujo. Al seleccionar "Overwrite Clock" aparece la pantalla que le corresponde, donde se establecen:
a) Período: 10 ns, por ejemplo.
b) Duty Cycle (ya está en 50% y en general se puede dejar en este valor).

El Apéndice B (mencionado antes como una de las referencias utilizada), explica una serie de pasos para dibujar (literalmente) las señales, pero no parece ser un método sustentable, dado que es totalmente manual. Cuando las señales son varias (¿más de dos?) y/o tienen mucha variación en el tiempo de simulación, dibujar cada uno de estos cambios se torna casi imposible sin tener errores o sin que sea demasiado extendido en el tiempo. En este caso, se simplifica la tarea a una señal periódica, pero habría que investigar la manera de especificar cambios de señales de manera más sustentable en términos de tiempo y errores. Una posibilidad a estudiar sería analizar el archivo de señales y agregar/cambiar datos/información directamente allí.
Habiendo hecho lo anterior, aparece en pantalla la señal de entrada de este circuito, bin, con todos los cambios posibles en el período de tiempo a simular.
Queda, entonces, hacer la simulación funcional.

          C.3) Assignments -> Settings...
En la pantalla que se abre, seleccionar Simulator Settings y en la derecha seleccionar Simulation mode: Functional. Click on ok
Processing -> Generate Functional Simulation Netlist
Esto corre algo así como un compilador que termina indicando que terminó correctamente.
Para realizar la simulación efectivamente
Processing -> Start Simulation
El simulador corre, genera la salida que corresponde y notifica que terminó correctamente. En la pantalla aparece la señal bout con el valor que el simulador generó para cada instante de tiempo. Recordar que se puede usar View -> Fit in Window
En este punto se termina la simulación funcional, que muestra que el circuido invierte la señal de entrada y eso significa que está bien.
Queda pendiente en este punto cómo hacer esta verificación de manera más sustentable que mirar en pantalla que la señal de salida tiene la "forma" (en este caso, invertida respecto de la entrada) que tiene que tener.
Resumiendo las tareas realizadas: especificar en Verilog, controlar que la especificación sea "correcta" en el sentido de Verilog (como con un compilador para un lenguage como C) y simular funcionalmente el diseño. Esto significa que, de hecho, se puede hacer exactamente lo mismo que hasta este punto con cualquier simulador de Verilog. En este caso se utiliza QII porque las tareas a realizar a partir de este punto ya son exclusivas de QII, no se pueden llevar a cabo con los simuladores de Verilog dado que incluyen información específica de la FPGA que maneja QII y esto es, de hecho, copyrigthed como mínimo.
También en este punto termina la información relacionada casi directamente con el Apéndice B.

D) Simulación de tiempos/Simulación con los dispositivos físicos/de hardware
Básicamente se usa lo que está en el apéndice C
Processing -> Start Compilation
Utiliza bastante tiempo, aún para este proyecto con un inversor (varios segundos). A medida que avanza muestra el % de completado en la barra inferior y algunas pantallas de reporte de resultados. Finalmente, la aparece la pantalla con el ok
Esto en realidad genera bastante más que un netlist, básicamente para "capturar" el hardware a utilizar (aquel que se incluyó en el comienzo del proyecto y que se puede cambiar con Assignments -> Device...)
Ahora se debe indicar que se debe hacer la simulación con análisis de tiempo teniendo en cuenta el hardware a utilizar...
Assignments -> Settings...
Click on Simulator Settings
Simulation Mode: Timing (estaba en Functional por la sucesión de pasos anteriores)
Processing -> Start Simulation
Después de mostrar el avance de la simulación, hace básicamente lo mismo que el simulador funcional: muestra la señal de salida y notifica que terminó la simulación
Ahora el cambio en bout no se muestra de manera simultánea con el cambio de la entrada. De hecho, hay varias cosas interesantes a ver en la salida:
        a) A pesar de que la señal de entrada cambiar en el ns 5 (de 0 a 1) el primer cambio de la salida (de 1 a 0) se da recién en el ns 18.1; esto indicaría que hay un "delay" inicial de 18.1 - 5 ns de la señal.
        b) Todos los demás cambios de la señal de salida se dan cada 5 ns, es decir que siguen el paso de la señal de entrada. Esto podría indicar el tiempo de transferencia de la información pin a pin que se indica en el Apéndice C como "speed grade" del chip...
Solamente para verificar si es un problema del "speed grade" se cambia la señal de entrada a un período de 50 ns (y se alarga un poco el "end time simulation"...)
Se debe poner la ventana del editor de señales y cambiar la señal bin y el end time simulation...
Luego, Processing -> Start Simulation
Ahora el primer cambio de bin (de 0 a 1) se da en el ns 25 y el primer cambio de bout (de 1 a 0) se da en el ns 38.1, la pregunta es... ¿(18.1 - 5) = (38.1 - 25)? Dado que es igual (13.1 ns), este primer cambio tiene en cuenta el tiempo de un inversor de la FPGA seleccionada (EPF10k10...) más el tiempo de "viaje" de la señal desde un pin de entrada hasta un pin de salida
En este punto se puede terminar una sesión: Salvar todo y salir... A partir de ahora, lo que queda es cargar/programar una FPGA y verificar que el diseño funciona y que se corresponde la simulación de tiempos con el funcionamiento real del dispositivo. Es más, se puede verificar cuán bien hace la simulación de tiempos QII. Para esto, se debe "programar" la FPGA (en terminología de QII) y hacer todo lo necesario para:
        a) Definir los pines asociándolos (o viéndolos asociados) a las entradas y salidas del diseño.
        b) Grabar la FPGA que corresponde.
        c) proporcionarle la entrada necesaria, por los pines que se definan.
        d) Ver cómo funciona el dispositivo utilizando un analizador lógico, por ejemplo.

Dado que la idea a partir de aquí es corroborar el comportamiento real del dispositivo diseñado con el funcionamiento sobre la FPGA, se vuelve a la simulación de tiempos para simular ahora con una señal de entrada igual a la que se puede utilizar como entrada real de la FPGA. Una de las señales que se puede utilizar de manera directa es la propia del oscilador de la placa de desarrollo, que es de 8 MHz y que debería ser "ruteada" o "introducida" como la señal bin del dispositivo diseñado. A nivel de simulación esto no es un problema: solamente se cambia la señal en el editor que corresponde.

E) Retomando para una simulación de tiempos a partir de lo hecho hasta D), con la idea de simular exactamente con el reloj de entrada de la propia placa de desarrollo, que es de 8 MHz.
     E.1) Abrir el proyecto.
     E.2) Processing -> Start Compilation (recordar que usa varios segundos, quizás un minuto)
     E.3) Assignments -> Settings...
Simulator Settings -> Simulation Mode: Timing
     E.4) Se pone la señal de entrada como la de la propia placa de la FPGA: 8 MHz
File -> Open...
Files of Type: Wave/Vector File (elegir el que ya estaba hecho)
Edit -> End Time... (1 us)
En la señal bin, cambiar el ciclo a 125 ns
Salvar el archivo de señales
     E.5) Processing -> Start Simulation
     E.6) La primera transición de bin se da a los 62.5 ns (de 0 a 1) y la primera de bout (de 1 a 0) a los 75.6 ns, es decir 13.1 ns después. En todos los casos las transiciones de bout son 13.1 ns posteriores a las correspondientes de bin
Es decir: todo funciona como está previsto en la compilación, a 13.1 ns de diferencia
Ahora se puede retomar la idea de utilizar directamente la placa de desarrollo, y los pasos a seguir serán:
      F) Averiguar los pines usados y para qué
      G) Carga en la FPGA/programación de la FPGA
     H) Evaluación sobre la FPGA con el analizador lógico

F) La averiguación de los pines a usar por el cargador/QII de la FPGA se puede realizar (visualmente) con (Apéndice C)
Assignments -> Timing Closure Floorplan
View -> Package Top

Haciendo zoom se puede llegar a ver cada pin de la FPGA y su correspondiente asignación. Cada pin tiene un color y una forma. Los asignados son círculos verde con una letra D en blanco y con el puntero sobre ellos se llega a que el pin 84 es para la señal bin, que se muestra con el texto:
"[Fitter Placed] bin <Input> @ PIN_84[Dedicated Input,.]".
De la misma manera, en un círculo verde sin letra:
"[Fitter Placed] bout <Ouput> @ PIN_18[Row I/O]".
Toda esta información se usará luego para conectar los pods del analizador lógico y la propia señal de entrada a la FPGA. El esquema general de la placa de desarrollo está dado en la documentación, junto con el conexionado de los pines de la FPGA hacia el exterior por conectores específicamente puestos para esta tarea. Esta información se replica aquí de manera condensada (ver la información de la placa de desarrollo UPx10K10).


Figura 1: Esquema de la Placa de Desarrollo y Conexionado de los Pines.

CON1 (a la izq.) y CON2 (a la der.) tienen los pines conectados de acuerdo a la tabla dada en la misma figura. De acuerdo con esta información, se pueden relacionar los datos del QII en cuanto a mapping de los pines,
[Fitter Placed] bin <Input> @ PIN_84[Dedicated Input,.]
por ejemplo, implica que la señal bin ingresa por el PIN_84 de la FPGA, que según la tabla de la Fig. 1 anterior está conectado al pin 12 del conector CON2. De la misma manera,
[Fitter Placed] bout <Ouput> @ PIN_18[Row I/O]
la señal bout del diseño se envía por el PIN_18 de la FPGA, que según la misma tabla está conectado al pin 7 del conector CON1.

G) Carga en/Programación de la FPGA (Apéndice D)
Tools -> Programmer
Asegurarse de que en Hardware Setup... esté "ByteBlasterMV[LPT1]"
En la misma fila: inv.sof (el proyecto a cargar en formato .sof, que se hace "automáticamente"), con el dispositivo EPF10K10... y Program/Configure checked
En la fila siguiente, el otro dispositivo de la placa: EPC2, pero sin nada a cargar
Click sobre Start, y termina satisfactoriamente.

H) Evaluación sobre la FPGA con el analizador lógico
La Fig. 2 muestra una foto de la placa conectada al analizador lógico, donde no llega a visualizarse la interconexión de la señal del clock de la placa vía el pin 1 del conector CON1 hacia el pin 12 del conector CON2, donde es tratada como la señal bin del dispositivo diseñado.


Figura 2: Foto de la Placa de Desarrollo Interconectada al Analizador Lógico.

Es decir que, placa: clock a pin 1 con1
Cables:
      pin 1 con 1 a pin 12 con2
      pin 1 con1 a pod1-0 entrada
      pin 7 con1 a pod1-1 entrada
Los retardos son de 7.5 ns (medidos) en vez de 13.1 ns (simulados)

Sugerencias/reporte de errores/etc.: envíe un e-mail a ftinetti @ gmail . com con subject "Combo con FPGA"