Ene 27

Hello World. Hello FPGA – Parte II: Placas y fases de diseño

Continuamos con el tutorial sobre FPGAs (ver parte I). En esta entrada vamos a dar los primeros pasos para implementar un circuito (extremadamente) sencillo en una placa basada en FPGA. Creo que con esto se entenderá que el desarrollo con FPGAs difiere notablemente del desarrollo software.

Diseño con FPGA

Ya vimos que la FPGA está formada por una miríada de pequeñas memorias que se pueden interconectar. El diseño a mano es inviable, por lo que es necesario utilizar herramientas software que nos ayuden a desarrollar los circuitos.  El diseñador (que no programador) se encarga de definir los bloques que forman el sistema. Para ello, debe definir las funciones lógicas que el sistema requiere y su interconexión. No hay que confundir las funciones lógicas con las LUTs, ni la interconexión entre funciones con la interconexión entre LUTs. Son precisamente las herramientas de desarrollo con FPGAs las que se encargan de particionar las funciones lógicas en LUTs y hacer que el cableado entre LUTs sea coherente con las interconexiones originales entre funciones. Y por supuesto, las herramientas optimizan el sistema conforme lo va implementando en la FPGA, tal como haría un compilador con código que tiene que transformar en ensamblador para una arquitectura de CPU determinada.

Es momento de introducir la placa como parte del flujo de desarrollo o de diseño. La placa alberga a la FPGA además de a otros chips y componentes circuitales. La placa podemos diseñarla nosotros mismos, o comprarla ya diseñada y fabricada. Para empezar en este mundillo esta es la mejor opción, aunque tengo que decir que hacer un diseño propio permite dotar a la placa de los elementos que realmente nos interesan y así abaratar su coste, reducir su tamaño, etc.

Hay placas comerciales bastante majas orientadas a distintos ámbitos.

Nos vamos a centrar en la placa DE2-115 de Terasic  DE2-115, que se basa en una FPGA Cyclone IV de la empresa Altera (Intel FPGA). La figura muestra la placa:

 

Figura. Placa DE2-115 de Terasic (imagen extraida de la web de Terasis [enlace])

[solicitado concendido permiso para su uso]

En la placa se observa claramente la FPGA (justo encima del texto Cyclone IV) y se ve que muchos otros elementos: pantalla LCD, displays de 7 segmentos (me encantan), chips variados, botones, conmutadores, conexión GPIO (General-Purpose Input/Output). Algunos de los chips que acompañan a la FPGA en este caso son: memoria SRAM, memoria DRAM, memoria EPROM, CODEC de vídeo, CODEC de audio, controladores de USB, controladores de UART, generador de salida VGA, etc. Otras placas tendrán diferentes chips, los cuales determinan sus prestaciones. Por ejemplo, pueden tener salida HDMI, puertos micro-USB, buses de expansión de memoria, etc.

La placa dispone de un puerto JTAG (Joint Test Action Group) que permite acceder directamente a la FPGA para configurarla (o programarla) o acceder a una memoria EPROM que es la que utiliza la FPGA para auto-configurase tras el arranque. En general no es posible acceder directamente a los chips que acompañan al dispositivo reconfigurable. Sin embargo, éstos están conectados a la FPGA, por lo que su configuración la debe hacer este dispositivo.

El ejemplo que abordamos consiste en utilizar dos pulsadores, o botones, de la placa para encender un LED (Light Emitting Diode). Puesto que hablamos en la parte I de una simple puerta AND, vamos a hacer que el LED se encienda únicamente cuando se pulsen simultáneamente los dos pulsadores.

Los pulsadores están conectados mediante conductores a pines o patillas concretos de la FPGA, por lo que es posible “leer” su valor lógico (si está pulsado o no) y utilizar dicho valor como parte del circuito que implementemos en la FPGA. De igual manera los LEDs están conectados a pines concretos del chip. Estas conexiones son fijas, puesto que los conductores son pistas metálicas de la placa PCB (Printed Circuit Board) (si nos fijamos de nuevo en el texto “Cyclone IV” podremos ver unas líneas de color azul más claro que el resto de la placa, estas líneas son pistas metálicas; hay más pistas en la otra cara de la placa, e incluso en su interior). Estos pines son los pines de entrada/salida de la FPGA, los cuales pueden conectarse a las LUTs igual que cualquier señal interna.

Por una parte, tenemos que ser capaces de indicar a las herramientas, que vamos a utilizar en nuestro circuito señales que provienen del exterior, y esto lo hacemos indicando a la herramienta que la señal a (por ponerle un nombre cualquiera) está conectada al pin número X. ¿Y cómo sabemos esto? Leyendo el manual de la placa. Si leemos el manual de la FPGA (llamada datasheet en inglés) podremos saber cuántos pines tiene el chip y sus características (niveles lógicos, si son de entrada o salida, si son entradas de reloj, la corriente que pueden proporcionar, etc.), pero, aunque todo esto es muy importante, no basta. En el manual de la placa vamos a encontrar la información acerca del uso que se le da a cada pin, es decir, qué elementos de la placa están conectados a éstos.

En el manual de la placa DE2-115 encontramos tablas donde se indica los pines que se están usando. Por ejemplo, para los cuatro pulsadores que aparecen en la esquina inferior derecha de la Figura la tabla es la siguiente:

Figura: Tabla 4-2 del manual, donde se indican los pines a los que están conectados los botones

[solicitado concendido permiso para su uso]

Hay tablas similares para los LEDs y para el resto de elementos de la placa.

Concretemos un poco más. Vamos a realizar una operación AND con el valor de dos botones y el resultado lo vamos a conectar a un LED. Las señales de entrada de la AND se llamarán KEY0 y KEY1 y la señal de salida de la AND se llamará LED0. Bien, ahora hay que decidir que botones usaremos. Por ejemplo, KEY0 se conectará al pin del botón KEY[0] (M23) y KEY1 al pin del botón KEY[1] (M21). LED0 se conectará al pin que está conectado a uno de los ocho LEDs de color verde de la placa, por ejemplo, a LED0.

Esto parece de Perogrullo, lo admito, pero tiene su importancia, y equivocarnos o confundirnos a la hora de elegir los pines puede darnos quebraderos de cabeza.

Bien, sigamos. Ya está, lo conectamos todo y hacemos una operación AND. Pues no, todavía nos falta un pequeño paso. Se tiende a asumir que el 0 lógico se corresponde con los conceptos de FALSO y OFF, y que el 1 se corresponde con VERDADERO y ON. Pero esto es totalmente arbitrario. Para saber si un botón devuelve al pulsarlo un 0 (un voltaje bajo) o un 1 (voltaje bajo) hay que saber cómo es su circuito. Para no andarme por las ramas, vemos en el manual de la placa que los pulsadores proporcionar un 1 si no se pulsa, el cual es su estado natural, y un 0 si se pulsan. Podéis ver el circuito para entender esta situación.

FIGURA. Esquemática de la conexión de los botones  (figura 4-6 del manual)

[solicitado concendido permiso para su uso]

Igual ocurre con el LED. Para saber si se enciende con un 1 o con un 0 hay que consultar el manual de la placa. En este caso se enciende con un 1 lógico (consultar el manual).

 

Dicho esto, en la misma placa hay LEDs, como por ejemplo los de los display de 7 segmentos, que se encienden con ceros. Y en otras placas lo pulsadores pueden perfectamente generar un 1 al pulsarse. Moraleja: hay que consultar el manual de la placa.

 

Gráficamente vemos lo que tenemos que implementar:

Figura. Esquema del diseño del ejemplo.

¿Cómo conseguirlo? Hablemos de las herramientas.

 

Fases de diseño con FPGAs

  1. Entrada de diseño

En esta fase se describe el circuito. El circuito puede describirse gráficamente utilizando puertas lógicas o bloques elementales, como multiplexores, decodificadores, contadores, etc., pero si el circuito es complejo se suelen utilizar lenguajes de descripción hardware o HDLs (del inglés, Hardware Description Languages). No confundir con lenguajes de programación: la FPGA se configura, no se programa. De forma muy simple os digo que mientras que en un lenguaje de programación el orden o secuencia de las instrucción influye en su comportamiento, todo lo que se escribe en HDL genera funciones lógicas y además todas las funciones existen y se “ejecutan” a la vez, por lo que el orden de las instrucciones que usemos en HDL no es relevante (esto es una simplificación muy grande, pero nos vale de momento). Destaco como HDLs los lenguajes VHDL y Verilog. En la actualidad hay formas de diseñar con FPGAs más cercanas a los lenguajes de programación, pero voy a evitar hablar de ellas en este momento.

  1. Simulación funcional

Una vez descrito el circuito en HDL es necesario comprobar si el circuito está bien diseñado. La simulación funcional nos permite introducir los valores de las entradas a lo largo del tiempo y ver el resultado que éstos producen en las salidas (o en cualquier señal intermedia) del circuito. Esta simulación supone que las operaciones lógicas se realizan de forma instantánea. Se trabaje con señales binarias, que también pueden agruparse en buses y ver la información como un número binario o en cualquier otra base.

  1. Síntesis (o compilación)

Consiste en convertir las funciones lógicas descritas mediante un HDL en un conjunto de elementos lógicos interconectados que se denomina netlist. Los elementos lógicos serán puertas lógicas en el caso de que la tecnología destina sean ASICs o LUTs si son FPGAs. Como ya comenté antes, la síntesis incluye la optimización de las funciones lógicas. Por ejemplo, si hacemos la operación NOT(NOT A), en lugar de usar dos puertas lógicas encadenadas, no usará ninguna, puesto que NOT(NOT A) = A.

  1. Asignación de pines

En este paso se indica a qué pines están conectadas las señales de entrada y salida del circuito que va dentro de la FPGA. Si no se especifican los pines la herramienta de diseño asignará pines aleatorios. Esta información puede introducirse a través de un fichero de texto o bien mediante una interfaz gráfica. También se aportará información acerca del estándar lógico que se esté usando (es decir, el voltaje asignados a los ceros y los unos: TTL, LVTTL, CMOS, LVCMOS, etc.), si son pines de alta velocidad, etc.

  1. Posicionamiento y rutado

El posicionamiento (placement en inglés) se encarga de elegir exactamente el elemento de la FPGA que se va a utilizar para implementar una LUT. El rutado (routing en inglés) se encarga de conectar los pines y las señales intermedias a las LUTs. Al proceso se le suele englobar en lo que se denomina place and route (que lo veremos como P&R o como PAR).

En las FPGAs las LUTs están agrupadas para disponer de conexiones rápidas entre ellas. Si dos LUTs están en grupos distintos, pero cercano se usará una ruta un poco más lenta y si los grupos están muy separados se usará una ruta de larga distancia, que evidentemente presentará un retardo mayor. Según el fabricante estos grupos reciben nombres distintos (Configurable Logic Block (CLB), Logic Array Block (LAB), etc.) y además el número de LUTs y la topología de interconexión varía. Con esto vemos que el proceso de placement es algo   más complicado de lo que parece a simple vista. Tradicionalmente existía una etapa anterior al placemente que se encargaba de agrupar primero las LUTs de manera que el posicionamiento se aplicaba a los grupos y no a las LUTs individuales. Algunos fabricantes lo llaman mapping y para crear un poco de confusión en algunos casos el mapping también hace placement, y el proceso de P&R sólo hace se encarga del rutado.

  1. Análisis temporal y simulación temporal

Una vez se sabe como quedará cada elemento en la FPGA y cómo estará interconectado las herramientas comprueban que las señales se propagan cumpliendo con la velocidad del reloj del sistema. Si una señal es demasiado lenta, el análisis temporal lo detecta y lo indica al diseñador. Este análisis proporciona los datos necesarios para poder llevar a cabo una simulación que incluya los tiempos que tarda cada señal en recorrer las pistas metálicos (las rutas que llamé antes) y que nos permita comprobar de forma mucho más fiel a la simulación funcional del punto 2 si el circuito está funcionando correctamente.

  1. Configuración del dispositivo

La configuración consiste en enviar los datos contenidos en un fichero llamado bitstream que contiene los valores de configuración de todos los elementos de la FPGA: los valores de cada LUT, el estado de cada conmutador que realiza la interconexión entre LUTs, la configuración de los puertos de entrada y salida, etc. Este bitstream se envía envía mediante un puerto serie directamente a la FPGA, o se envía a una EPROM que queda programada. La FPGA tras el reinicio de la placa estará virgen, puesto que la configuración se almacena en memoria no volátil (SRAM) y tras el apagado del chip se borra; la configuración la lee de la EPROM antes mencionada.

 

Implementación

Aunque sea de mala educación, os voy a dejar con la miel en los labios y vamos a terminar el ejemplo en la siguiente entrada. Que soñéis con circuitos reconfigurables.

 

Enlaces de interés

  • Información sobre la placa DE2-115 [consultado 25/01/2019]
  • DE2-115 User manual (manual de usuario de la placa DE2-115), Terasic Inc. [consultado 25/01/2019]

 

Agradecimientos

Gracias a Terasic Inc. por concederme los permisos para utilizar las fotografías de su web así como las figuras y tablas de la documentación de sus placas.

Deja un comentario

Your email address will not be published.

Bitnami