01signal.com

Reconfiguración parcial en Xilinx: reset y desacoplamiento

Esta es la tercera entrada de una serie de cuatro sobre la reconfiguración parcial (partial reconfiguration), también llamada Dynamic Function eXchange (DFX), con Vivado de Xilinx. Mientras que las dos anteriores muestran cómo configurar el diseño de FPGA, esta trata de cómo la lógica estática puede afrontar el hecho de que la lógica reconfigurable desaparezca y reaparezca.

Visión general

El proceso de carga de un flujo de bits parcial (bitstream) es similar al intercambio en caliente de hardware físico: una parte determinada se retira de forma abrupta, se sustituye por otra y se enciende. Esta entrada analiza los medios necesarios para garantizar que esta transición se realice sin problemas y de forma fiable.

Esta entrada supone que la reconfiguración parcial la lleva a cabo la lógica estática de la propia FPGA. Para garantizar un funcionamiento correcto, el proceso debería seguir estas fases (a continuación se explican):

La necesidad del desacoplamiento

Durante el proceso de carga del flujo de bits parcial, las conexiones entre la lógica estática y la lógica reconfigurable se encuentran en un estado impredecible. Como consecuencia, los puertos de salida del módulo reconfigurable pueden generar patrones aleatorios o valores no válidos. Esto no ocurre necesariamente en todos los puertos de salida ni en todo momento, pero lo más probable es que se observe algún comportamiento extraño.

Como la lógica estática sigue funcionando aunque se cargue el flujo de bits parcial, es necesario ignorar las señales impredecibles que puedan llegar del módulo reconfigurable para evitar efectos adversos. La guía de usuario de Xilinx, UG909, denomina a esto desacoplamiento (decoupling).

La forma de implementar el desacoplamiento depende de la naturaleza de los puertos de salida del módulo reconfigurable: debe analizarse la influencia de cada uno de estos puertos sobre la lógica estática y tomar las medidas preventivas necesarias. Esto puede implicar, por ejemplo, multiplexar los puertos de salida con valores neutros durante la reconfiguración, añadir una habilitación de reloj (clock enable) a la lógica que no deba responder, o mantener en reset algunas partes de la lógica estática.

Si la lógica reconfigurable está conectada directamente a pads de E/S, puede ser necesario ponerlos en modo alta impedancia (high-Z) o desactivar la habilitación de reloj de la lógica de E/S (si esa lógica de E/S incluye un registro de salida). Además, si la lógica reconfigurable está conectada a componentes externos, puede ser necesario llevar esos componentes a un estado seguro antes de la reconfiguración.

En el catálogo de IP (IP Catalog) de Vivado hay disponible una IP de desacoplamiento para reconfiguración parcial (Partial Reconfiguration Decoupler IP) destinada al desacoplamiento de conexiones AXI.

Los puertos de entrada del módulo reconfigurable no necesitan ese tratamiento: a la lógica estática no le importa que las señales que genera no se consuman.

En los dispositivos Ultrascale, el desacoplamiento es necesario antes de cargar los flujos de bits de borrado (clearing bitstreams), ya que apagan la lógica reconfigurable.

Unas palabras sobre la secuencia STARTUP

Una parte importante del flujo de bits (tanto del completo como del parcial) es el comando de configuración START, que pone en marcha la secuencia STARTUP. Esta secuencia implica un par de mecanismos cuyo fin es una puesta en marcha coherente de la lógica.

La primera parte es que los elementos síncronos reciben sus valores por defecto al final de la configuración. Esto siempre es así en las FPGA Ultrascale y posteriores. En las FPGA de la serie 7 lo es para una configuración completa (es decir, con un flujo de bits inicial), y para la reconfiguración parcial si RESET_AFTER_RECONFIG está habilitado.

La segunda parte es GWE (Global Write Enable, habilitación global de escritura; no debe confundirse con las entradas de habilitación ni con las de habilitación de escritura de los elementos síncronos). Esta señal permite que los biestables y las RAMs cambien de valor. GWE se mantiene a nivel bajo en toda la FPGA durante la configuración completa, y pasa a nivel alto en algún momento de la secuencia de arranque de la configuración. Cuando se carga un flujo de bits parcial, solo se ve afectada la lógica reconfigurada.

Naturalmente, el cambio de GWE es asíncrono respecto a cualquier reloj proporcionado por la lógica de la aplicación, así que la temporización entre ese cambio y el primer flanco de reloj efectivo es impredecible para cualquier elemento síncrono.

En un escenario de reconfiguración parcial, igual que con una configuración completa, esto significa que todos los elementos síncronos tendrán su valor inicial inmediatamente después de que el proceso haya terminado (con Ultrascale y posteriores, o si se ha establecido RESET_AFTER_RECONFIG). No obstante, existe la posibilidad aleatoria de que algunos elementos síncronos respondan al primer ciclo de reloj de la lógica de la aplicación y otros no. Este comportamiento aleatorio depende de cuándo llega ese primer flanco de reloj en relación con el momento en que GWE pasa a nivel alto. Por tanto, es importante aplicar correctamente el reset a toda la lógica sensible a esta incertidumbre.

La necesidad de aplicar reset a la lógica reconfigurable después de cargar el flujo de bits parcial es la misma que tras una configuración completa de la FPGA. Sin embargo, resulta más intuitivo que haya que resetear en el caso de una configuración completa, sobre todo porque el reset suele mantenerse activo hasta que algunos elementos lógicos se han estabilizado (por ejemplo, cuando los MMCM o PLL están bloqueados, el hardware externo está listo, etc.).

En resumen, no hay una respuesta única sobre si conviene resetear la lógica reconfigurable o qué partes de ella. Igual que en una configuración completa, los elementos síncronos reciben sus valores por defecto y empiezan a responder a los relojes. En algunas situaciones esto es suficiente, y en otros escenarios hace falta un reset.

Detectar el final de la secuencia STARTUP

De las fases enumeradas antes, la única que escapa al control de la lógica de la aplicación es la secuencia STARTUP. Aun así, es importante saber cuándo ha terminado.

En la guía de configuración de cada familia de FPGA hay una descripción de la secuencia STARTUP, pero para resumir, el tiempo que tarda esta secuencia depende mucho de las opciones del flujo de bits. Por ejemplo, la secuencia puede configurarse para esperar a que los MMCM se bloqueen, o a que los DCI completen su ajuste de impedancia.

La FPGA proporciona una señal, End Of Startup (fin de la secuencia de arranque, EOS), que pasa a nivel alto en la última fase de la secuencia STARTUP (es decir, cuando esta secuencia ha terminado). Confiar en EOS es la forma formalmente correcta de saber cuándo reactivar la lógica reconfigurable, iniciando un reset y comenzando el reacoplamiento de los puertos de salida.

La señal EOS solo está disponible desde dentro de la trama lógica, mediante una instanciación de la primitiva STARTUPE2 (primitive), posiblemente como sigue:

wire eos;

STARTUPE2 #(.PROG_USR("FALSE")) startup_ins
  (
   .CLK(1'b0),
   .GSR(1'b0),
   .GTS(1'b0),
   .KEYCLEARB(1'b1),
   .PACK(1'b0),
   .USRCCLKO(1'b0),
   .USRCCLKTS(1'b0),
   .USRDONEO(1'b1),
   .USRDONETS(1'b1),
   .CFGCLK(),
   .CFGMCLK(),
   .EOS(eos),
   .PREQ());

Por tanto, cuando el flujo de bits haya terminado de cargarse en el ICAP, espera a que EOS pase a nivel alto y, a continuación, comienza el reset y el reacoplamiento.

Las FPGA Ultrascale tienen en su lugar una primitiva STARTUPE3; sin embargo, Vivado también acepta primitivas STARTUPE2 para estas FPGA y las traduce correctamente a STARTUPE3. Así que el ejemplo de código anterior cubre todas las familias de FPGA.

Hice algunas pruebas anecdóticas para medir cuánto tarda EOS en pasar a nivel alto después de que el comando START del flujo de bits llegue al ICAP.

Con Kintex-7, con los ajustes por defecto del flujo de bits, esto tardó 26 ciclos de reloj (a 100 MHz, es decir, unos 260 ns). Como había datos adicionales en el flujo de bits, entre ellos NOP, es muy posible que EOS pasara a nivel alto muy poco después de que la última palabra del flujo de bits se introdujera en el ICAP.

Pero la misma prueba con una FPGA Kintex Ultrascale dio resultados completamente distintos: EOS tardó aleatoriamente entre 0,8 ms y 4,5 ms en pasar a nivel alto después del comando START.

Aunque es bastante fácil usar la primitiva STARTUPE2 como se muestra arriba, también es posible iniciar el reacoplamiento tras un tiempo fijo desde que el flujo de bits ha terminado de cargarse. Por ejemplo, es difícil de imaginar que la secuencia STARTUP tarde hasta 100 ms, y aun así es un retardo prácticamente imperceptible para una persona. Sin embargo, teniendo en cuenta los dos resultados de las pruebas anteriores, parece que usar la primitiva STARTUPE2 es la opción segura.

En cuanto a las FPGA Ultrascale, el comportamiento de EOS después de cargar un flujo de bits de borrado no está documentado al parecer. Pero en una prueba anecdótica se mantuvo a nivel bajo después de cargar el flujo de bits de borrado, y pasó a nivel alto después del flujo de bits parcial que se cargó a continuación.


La tercera entrada termina aquí. La última entrada se adentra entre bastidores en cómo Vivado gestiona la relación entre la lógica estática y la lógica reconfigurable mediante OOC y DCP, y cómo entenderlo abre el camino a una forma fiable de producir flujos de bits parciales para el escenario de actualización remota (Remote Update).

Esta página se ha traducido del inglés mediante traducción automática. En caso de duda, consulta el texto original.
Copyright © 2021-2026. All rights reserved. (dcc38493)