Dentro de la esfera computacional, los FPGA y los SoC programables son una clase de dispositivos que están separados de los dispositivos de CPU, MCU, DSP y GPU. Los FPGA proporcionan a los desarrolladores implementaciones que ofrecen un mayor rendimiento, menor latencia y un mayor determinismo.
Dentro de la esfera computacional, los FPGA y los SoC programables son una clase de dispositivos que están separados de los dispositivos de CPU, MCU, DSP y GPU. Los FPGA proporcionan a los desarrolladores implementaciones que ofrecen un mayor rendimiento, menor latencia y un mayor determinismo.
Tanto el FPGA como los SoC programables contienen celdas lógicas programables, como tablas de búsqueda, registros y RAM de bloques. Cuando un desarrollador crea una solución lógica programable, él define la configuración y las conexiones de estas celdas lógicas.
A medida que el desarrollador describe la configuración de las celdas lógicas en lugar de la secuencia de instrucciones para la ejecución, esto conduce a un flujo de desarrollo significativamente distinto. Esta diferencia también presenta nuevos desafíos para los desarrolladores, que incluyen:
- Verificación: ¿cómo el diseñador verifica y depura la funcionalidad?
- Asignación de recursos: ¿el dispositivo contiene suficientes recursos lógicos para implementar el diseño?
- Cierre de temporización: ¿pueden conectarse las celdas lógicas utilizadas según sea necesario y aún así alcanzar la frecuencia de operación deseada?
- Disipación de potencia: ¿la disipación de potencia del diseño final es aceptable para los suministros de energía y el entorno térmico?
Captura del diseño
Desde su introducción el año 1984, la forma en que se capturan los diseños lógicos programables ha cambiado de manera significativa. Este progreso ha visto evolucionar la entrada de diseños desde la definición de ecuaciones lógicas para cada celda lógica hasta la captura esquemática de circuitos lógicos, el uso de lenguajes de descripción de hardware y, más recientemente, la síntesis de alto nivel.
Por supuesto, uno de los factores clave que impulsan el creciente nivel de abstracción utilizado para programar dispositivos ha sido la capacidad y habilidad en aumento de estos dispositivos.
La mayoría de los diseños modernos se capturan con un lenguaje de descripción de hardware (HDL) como Verilog o VHDL. Ambos lenguajes permiten al desarrollador describir la funcionalidad deseada que se implementará en un nivel de transferencia de registro (RTL). La definición de un diseño RTL significa que el desarrollador está describiendo un diseño lógico sincrónico y la transferencia de información entre registros,por ejemplo, máquinas de estados y contadores.
Si bien los lenguajes HDL contienen las construcciones que se esperarían de un lenguaje de programación (por ejemplo, trabajar con archivos), solo se puede usar un subconjunto limitado del lenguaje para crear una solución lógica programable. Las construcciones restantes se utilizan durante la verificación del diseño.
Sin embargo, cada vez más, los desarrolladores de soluciones lógicas programables están utilizando lenguajes de nivel más alto como C, C++, OpenCL y Matlab/Simulink para la captura de diseños. Estos lenguajes se utilizan junto con una herramienta de síntesis de nivel más alto, por ejemplo Vivado HLx o el Compilador HLS de Intel, que es responsable de convertir el lenguaje de alto nivel en una descripción VHDL o Verilog. Esta descripción de HDL se implementa por medio del flujo de desarrollo de FPGA estándar.
Al igual que todos los demás desarrollos, independientemente de si se utiliza un lenguaje HDL o de alto nivel, es una buena práctica utilizar un enfoque modular, que permita una comprensión y reutilización más fáciles, según se desee.
Bancos de pruebas
A medida que se desarrolle cada módulo HDL o HLS, será necesario realizar pruebas para garantizar que el funcionamiento se lleve a cabo como se espera. Aquí es donde entra el banco de pruebas. Este aplicará estímulo a las entradas y al monitor del módulo. En casos avanzados, informará sobre el comportamiento de las señales de salida. Como estamos simulando las transacciones para cada registro en el diseño, las simulaciones lógicas pueden ser mucho más lentas.
Aunque conceptualmente es como un arnés de prueba de software, el banco de pruebas puede requerir una interacción más detallada porque cada señal y bus deben conducirse y sincronizarse correctamente para estimular el módulo. Es dentro del banco de pruebas que se utilizan las construcciones más amplias del lenguaje a medida que se leen las configuraciones de estímulo o los resultados se registran en archivos de texto.
Uno de los elementos clave de la simulación es la prueba de casos de esquina y condiciones de límite, lo que puede hacer que el módulo no funcione según lo previsto.
Para aplicar el banco de pruebas a la unidad que está bajo prueba, se requiere un simulador HDL como Vivado Simulator (que se suministra con Vivado HLx) ya que esto permite a los desarrolladores simular el diseño lógico.
Es una práctica común simular el diseño antes de la implementación dentro del dispositivo. Sin embargo, esto significa que los resultados de la simulación no consideran los retrasos de tiempo que ocurren en el dispositivo implementado (por ejemplo, tiempos de configuración y retención). Como tal, solo simula el rendimiento funcional. Si bien las simulaciones se pueden anotar con esta información una vez que el diseño se implementó, hacerlo aumenta significativamente el tiempo de ejecución de la simulación.
Implementación
Una vez que el desarrollador está satisfecho con el rendimiento funcional, la etapa final del desarrollo es la implementación.
La implementación se puede dividir en cuatro etapas distintas: síntesis, colocación, enrutamiento y generación de archivos de programación. Si bien la implementación consta de múltiples etapas, todas se realizan por medio de una herramienta patentada suministrada por el proveedor del dispositivo seleccionado, por ejemplo, Quartus de Intel o Xilinx Vivado.
La síntesis toma los archivos HDL y los sintetiza en una descripción de los circuitos lógicos que se implementarán. Como tal, la síntesis determina la configuración de las celdas lógicas configurables, los registros y los bloques RAMS y otros recursos lógicos destinados disponibles dentro del dispositivo de destino. Es durante la etapa de síntesis que se llevará a cabo la mayor parte de la optimización lógica y se realizará el corte de las señales y variables no utilizadas. Esto puede dar lugar a optimizaciones no deseadas o decisiones de síntesis. Como tal, el desarrollador puede controlar las opciones de síntesis, las estrategias y las optimizaciones por medio de restricciones de síntesis. Las restricciones están basadas en texto y guían la herramienta de síntesis durante su funcionamiento.
El resultado de la síntesis es una lista de conexiones, que describe el comportamiento lógico del diseño. La siguiente etapa de la implementación es colocar físicamente cada función lógica dentro del dispositivo. En general, la herramienta de colocación utilizará algoritmos integrados que definen cómo coloca las celdas lógicas dentro del diseño. Sin embargo, si lo desea, el usuario también puede examinar y cambiar la ubicación de las celdas lógicas a través del uso de restricciones de ubicación. Esto es muy útil cuando estamos tratando de lograr el cierre de temporización en el diseño.
La penúltima etapa de la implementación se realiza una vez asignadas las funciones lógicas. Estos recursos asignados se deben conectar según lo definido por el diseño mediante los recursos disponibles en el dispositivo. Este proceso se denomina "enrutamiento" y es aquí cuando los algoritmos de enrutamiento utilizan el rendimiento de temporización deseado para intentar alcanzar la frecuencia de operación deseada. Alcanzar la frecuencia de operación deseada se denomina "cierre de temporización", lo que significa que cada elemento de registro y reloj en el diseño logra la configuración y el tiempo de retención requeridos.
En caso de que no se logre el cierre de temporización, se pueden utilizar varios enfoques, desde seleccionar una estrategia de implementación distinta hasta actualizar las restricciones de ubicación para acercar los bloques críticos de temporización, así como actualizar el diseño HDL para implementar una estructura lógica más óptima durante la síntesis.
La etapa final del proceso de implementación es la generación de un archivo de programación, que se puede utilizar para configurar el dispositivo de destino. Una vez completado esto, estamos listos para descargarlo en nuestro dispositivo y comenzar la diversión que es la integración con el sistema más amplio.
Por supuesto, la integración puede traer sus propios desafíos tanto para el desarrollador de FPGA como para el integrador de sistemas.
Conclusión
El proceso de desarrollo de FPGA es ciertamente distinto del que se usa para la creación de una solución computacional más tradicional. Sin embargo, la curva de aprendizaje, ya que se relaciona con los idiomas y las cadenas de herramientas (especialmente con HLS) no es tan empinada como inicialmente se pensaba. Con suficiente tiempo dedicado a estudiar estos procesos, los desarrolladores pueden comenzar a implementar soluciones basadas en FPGA que ofrecen un mayor rendimiento, menor latencia y un aumento en el determinismo.
