Cuando las cosas se ponen raras
Por lo general, las FPGA son componentes extremadamente fiables; sin embargo, como cualquier otra tecnología, no funcionan bien si se usan de forma incorrecta.
Desgraciadamente, las herramientas de diseño para FPGA no ayudan demasiado a los humanos a evitar cometer errores, lo que con demasiada frecuencia da lugar a resultados poco fiables e impredecibles. En concreto, las herramientas para FPGA solo garantizan un funcionamiento fiable si se siguen ciertas prácticas de diseño, y asumen que sabemos lo que estamos haciendo. A diferencia de los compiladores de software, que se niegan a generar código ejecutable si hay un error en el código fuente, las herramientas para FPGA se limitan a decir: «Aquí tienes tu flujo de bits (bitstream); pruébalo si quieres. Por cierto, hay 200 advertencias, y si entiendes lo que significa la advertencia #143, también entenderás que hay un problema grave que hay que corregir».
No es raro que la gente que trabaja con FPGA tenga la sensación de que la electrónica está poseída por alguna fuerza mágica y de que nada tiene sentido. Un problema puede aparecer y desaparecer como consecuencia de cambios totalmente ajenos, sin que haya una explicación racional a la vista. Muchos ingenieros con una formación adecuada acaban adoptando teorías absurdas sobre las FPGA para intentar explicar ese comportamiento tan extraño.
Esto es el «modo magia negra»: cuando personas sensatas dejan de creer que su problema tiene una explicación racional y buscan en su lugar un apaño basado en la experiencia. ¿Todo funciona bien cuando la FPGA está muy fría? Pues ponle un disipador enorme. ¿El problema solo aparece con algunas placas y no con otras? Vale, prueba todas las placas y tira las que no funcionen. Y así sucesivamente.
Cómo se manifiesta
Esta es una lista parcial de situaciones que pueden llevar a un ingeniero a una mentalidad irracional. Siempre es del tipo: «todo funciona de maravilla, excepto cuando...»
- ... de repente deja de funcionar, sin motivo aparente.
- ... haces un cambio sin relación y aparentemente aleatorio en el código Verilog (o VHDL), en las opciones o en la versión de las herramientas de la FPGA.
- ... el aire acondicionado está encendido / apagado.
- ... el sistema lleva un tiempo funcionando / se enciende completamente frío.
- ... se utilizan FPGA de otro lote de fabricación.
- ... se utiliza otro componente de otro lote de fabricación.
- ... pongo el dedo aquí / pongo la mano encima de aquello / pulso ese botón que no tiene nada que ver.
Esto suele venir acompañado de la creencia de que la propia electrónica está defectuosa y no cumple lo que promete su hoja de datos. No son raras las teorías conspiratorias sobre cómo una gran empresa fabrica componentes defectuosos.
Así que esto no es un simple bug. En realidad, los bugs pueden volver loco a cualquiera, pero suelen tener cierto grado de repetibilidad y desde luego no aparecen ni desaparecen por culpa del aire acondicionado. Nunca he oído a un ingeniero de software culpar al propio PC de un bug (aunque en rarísimas ocasiones sea así). En cambio, los errores en el diseño de una FPGA sí pueden provocar fallos a nivel de hardware. De ahí a culpar al mundo entero hay un paso.
Hay una explicación lógica. De verdad.
Y está a tu alcance. No necesariamente fácil.
He trabajado como autónomo en este campo durante bastante tiempo y de vez en cuando me han encargado arreglar situaciones así. Créeme cuando te digo: salvo en casos extremadamente raros, la FPGA está perfectamente; el problema probablemente está en el flujo de bits.
La mala noticia es que, con bastante frecuencia, hay más de un fallo en el diseño de la FPGA, y esos fallos pueden ser la causa del problema visible. En consecuencia, puede haber muchas cosas que corregir. En más de una ocasión me han pedido que arregle un diseño de FPGA que «casi funciona», para darme cuenta en seguida de que se espera que ese «pequeño problema» se resuelva rápido. Estabilizar un diseño suele suponer trabajar mucho sin avances visibles.
De una manera u otra, no queda más remedio. En esta página voy a intentar devolver el pensamiento racional, entre otras cosas enumerando posibles causas de lo que parece un fantasma en la electrónica.
Por supuesto, lo mejor es evitar llegar a esta situación desde el principio. Seguir las Reglas de Oro que he recogido en otra página es un buen comienzo.
Por qué las cosas se vuelven raras
Bueno, la respuesta corta es que algo falla en el diseño de la FPGA. Y cuando eso ocurre, en principio hay dos posibilidades. La relativamente afortunada es que haya un fallo visible y constante en lo que se supone que debe hacer la FPGA. Es como un bug de software: encuéntralo, arréglalo, comprueba que funciona después del arreglo y listo.
La menos afortunada es que la FPGA funcione, pero sobre todo por una casualidad afortunada. Por tanto, cuando cambian algunas condiciones, la FPGA deja de funcionar correctamente de repente, y quizá después vuelve a funcionar bien. ¿Pero por qué ocurre esto?
Y este es el quid de la cuestión: una FPGA es un componente electrónico y, como tal, tiene imprecisiones durante su fabricación. Aún más importante: cuando cambia la temperatura del silicio, cambia también la velocidad a la que los transistores cambian de estado, y lo mismo ocurre con la velocidad a la que las señales se propagan por la lógica. Las variaciones en la tensión de alimentación también influyen en la rapidez con la que ocurren las cosas dentro de la FPGA.
Por tanto, si la FPGA se calienta o se enfría un poco, una señal puede llegar a un flip-flop ligeramente más tarde o más pronto con respecto al reloj. Eso por sí solo puede hacer que ese flip-flop no capte la señal que debería haber muestreado, o que capte la señal que normalmente no capta. Incluso el calentamiento local del silicio puede provocarlo cuando la lógica vecina del chip (posiblemente no relacionada) se activa más o menos.
Del mismo modo, las FPGA tienen imprecisiones de fabricación. Aunque todas las FPGA que salen de fábrica han pasado pruebas que garantizan su compatibilidad con las especificaciones, unas pueden tener el silicio más rápido que otras. Por eso un diseño de lógica mal hecho puede funcionar en una FPGA y no en otra.
Todos estos parámetros aleatorios influyen en cuándo cambian de estado los pequeños componentes de la lógica, y esa diferencia en los tiempos puede marcar la diferencia entre algo que funciona perfectamente y una catástrofe. Por lo tanto, pequeñas desviaciones de fabricación, de temperatura o de tensión pueden marcar una diferencia visible.
¿Cómo puede ser entonces una FPGA fiable? Cuando el diseño de la FPGA se hace correctamente, las herramientas de diseño se aseguran de que todo funciona siempre según lo definido. O mejor dicho, de que todo funciona en cualquier FPGA que haya superado las pruebas de fabricación y se utilice dentro de los requisitos de la hoja de datos. Eso se reduce a que la temperatura ambiente esté dentro del rango exigido (con refrigeración si hace falta) y a que las tensiones en los pines de la FPGA sean correctas.
Ahora bien, si no se siguen las prácticas exigidas en el diseño de FPGA, las herramientas tampoco garantizan un funcionamiento correcto. Esto significa que los parámetros que no deberían influir se vuelven cruciales, y toda la placa deja de funcionar y vuelve a funcionar dependiendo de cosas que no deberían importar en absoluto. Lo raro que puedan volverse las cosas no tiene límite.
Así que, a riesgo de repetirme, aquí van algunos ejemplos:
- Puede que todo funcione perfectamente y, de repente, haces un cambio trivial, vuelves a ejecutar la implementación, cargas el nuevo flujo de bits y ¡pum!, falla por completo. Normalmente se debe a que la lógica se coloca en un sitio distinto dentro de la FPGA, y el encaminamiento entre los elementos lógicos también cambia: la colocación y el enrutado (place and route) son distintos. Como resultado, cambian los retardos de propagación (propagation delay), y algunas señales que antes llegaban con la sincronización adecuada a su destino dejan de hacerlo.
- Tienes tres placas idénticas: una funciona perfectamente, la segunda solo funciona por las mañanas y la tercera no funciona nunca. Probablemente se deba a pequeñas diferencias en el silicio de las FPGA. En consecuencia, en algún lugar del diseño hay una señal interna que en la primera placa llega a su destino con el temporizado adecuado. En la segunda, el margen es menor, así que un cambio de temperatura ambiente lleva a la FPGA al otro lado del umbral entre funcionar y no funcionar. Y la tercera FPGA está todo el rato en el lado equivocado de ese umbral.
- «Enciendo este aparato y aquel otro deja de funcionar, pero no tienen nada que ver». Esto suele tener que ver con la temperatura. Aunque la lógica de una función no tenga relación con la de otra, un elemento lógico activo puede calentar a sus vecinos.
Merece la pena repetirlo una y otra vez: cuando el diseño de la FPGA se hace correctamente, nada de esto ocurre. O al menos, ocurre rarísima vez. Poca gente se da cuenta de lo fiable que es la electrónica cuando se leen y se siguen las hojas de datos y, además, se usa bien la FPGA.
Pero supongo que este sermón llega un poco tarde para quienes están leyendo esta página: el problema ya está ahí. Así que, basándome en mi propia experiencia, he enumerado algunas causas comunes de una FPGA aparentemente embrujada. Si te enfrentas a un problema así, hay muchas probabilidades de que sea uno de estos.
Motivo #1: La temporización
En gran medida, las herramientas garantizan el funcionamiento estable de la FPGA al cumplir las restricciones de temporización (timing constraints) que les has proporcionado. Este es el pacto entre tú y las herramientas: expresas los requisitos de temporización con precisión, y las herramientas se aseguran de cumplirlos en cualquier FPGA que utilices, siempre que la FPGA opere dentro del margen permitido de temperaturas y tensiones.
No es raro que las restricciones de temporización se limiten a una única restricción que contiene la frecuencia del reloj de referencia. Eso puede ser suficiente, pero si te has limitado a copiar esa línea de otro diseño y, oye, funciona, hay un buen motivo para revisarla.
En realidad, esto consiste en hacer la temporización correctamente en general. Y no es una tarea trivial, ni siquiera para el diseñador de FPGA más experimentado. Significa asegurarse de que cada camino de señal (path) del diseño esté controlado por una restricción que garantice que el flip-flop del final reciba siempre la señal correctamente. Salvo aquellos caminos que no necesitan restricción.
Así que lo primero que hay que comprobar: ¿ha cumplido el diseño las restricciones de temporización? Esto es muy básico, pero como la mayoría de las herramientas para FPGA generan el flujo de bits igualmente, los novatos pueden caer en este sencillo error.
Lo siguiente es revisar las restricciones de temporización. Hay una página aparte que trata esta revisión. Pero en resumen: ¿entiendes exactamente qué significan las restricciones de temporización? ¿Su significado es exactamente el que debería ser? Si hay restricciones selectivas —es decir, que cubren algunos caminos de forma específica con condiciones de filtro—, ¿actúan de verdad sobre los caminos correctos?
Después hay que leer con atención el informe de temporización. Una vez más, esa página aparte profundiza en este tema.
Otra cosa que hay que revisar son los cruces entre dominios de reloj (clock domain crossings). ¿Hay señales que pasan de un dominio de reloj a otro de forma insegura? Esto podría deberse a no prestar atención a qué lógica está asociada con cada reloj. ¿Estos cruces se hacen solo con las FIFO que crean las herramientas de FPGA? Si no es así, ¿están hechos correctamente y de forma segura?
Motivo #2: Resets mal gestionados
Puede que no parezca relacionado, pero si no se garantiza el estado inicial de la lógica, es muy posible que el resultado sea un comportamiento de magia negra.
La regla es simple: si no te has tomado en serio los resets y el arranque de la lógica, lo más probable es que lo hayas hecho mal.
En particular, considera este ejemplo:
always @(posedge clk or negedge resetn)
if (!resetn)
the_reg <= 0;
else
the_reg <= [ ... ] ;
Si tu idea de los resets es escribir un código como este, sin ocuparte explícitamente de qué ocurre cuando @resetn se desactiva (es decir, cuando pasa a nivel alto en este ejemplo), deberías sin duda mirar esta página.
En cualquier caso, es buena idea comprobar que hay resets donde debería haberlos y que hacen bien su trabajo. Qué significa exactamente eso se trata en una breve serie de páginas sobre este tema.
Motivo #3: Las señales de reloj
La calidad de los relojes es posiblemente el tema más infravalorado del diseño digital. Suele ser algo así como: «sí, cambia de alto a bajo y viceversa; usémoslo como reloj».
Los relojes que se usan con la lógica de la FPGA deben ser estables y tener una fluctuación de fase (jitter) adecuada. No menos importante, la conexión física del reloj a la FPGA debe ser estable y fiable.
Así que en una expresión como esta,
always @(posedge clk)
lo que se utilice como @clk debe tratarse con mucho cuidado. Lo ideal es que ese reloj proceda de un componente dedicado a la generación de relojes (un oscilador), que garantiza una señal estable y con poca fluctuación de fase (jitter). En general, es mejor usar ese reloj externo como reloj de referencia de una PLL que conectarlo directamente a la lógica. Esto es cierto incluso si la PLL no cambia la frecuencia del reloj.
La razón es que usar una PLL permite vigilar el detector de bloqueo de la PLL. Así, la lógica que depende de ese reloj se puede mantener en estado de reset mientras la PLL no esté bloqueada. Hacerlo reduce bastante las probabilidades de problemas si el reloj de referencia tiene problemas de estabilidad (sobre todo justo después del encendido).
Puede parecer que la PLL es la culpable y que provoca resets aparentemente innecesarios porque pierde el bloqueo de forma esporádica. Eso se puede «arreglar» de forma equivocada quitando la PLL y conectando el reloj externo directamente a la lógica, y entonces todo parece funcionar bien. En un caso así, lo más probable es que haya un problema con el reloj de referencia. Quitar la PLL no resuelve el problema, sino que lo traslada a la lógica de usuario, lo que puede generar una situación de magia negra.
Hasta ahora he hablado de relojes procedentes de osciladores dedicados, que es el caso fácil. La cosa se complica con otras fuentes: los relojes generados por un procesador o por uno de sus periféricos deben usarse con cuidado, si es que se usan. Tales relojes pueden detenerse momentáneamente por culpa del procesador, o producir ocasionalmente formas de onda ilegales. Esto puede deberse a que el software escribe en los registros de hardware correspondientes, quizá como parte de una tarea sin relación. Es posible que esos eventos breves no se vean al examinar el reloj con un osciloscopio, pero provocan igualmente fallos extraños.
Otra fuente habitual de problemas es una mala gestión de un reloj síncrono de fuente (source synchronous clock). En otras palabras, cuando un componente externo suministra una señal de reloj y una o más señales de datos, de modo que los datos son síncronos con ese reloj. Normalmente, las señales de datos solo pueden cambiar de valor en los flancos de subida del reloj (o solo en los de bajada).
Un método habitual, pero bastante peligroso, es conectar el reloj síncrono de fuente directamente a la lógica de usuario dentro de la FPGA. Parte del problema es que ese reloj síncrono de fuente a menudo no se pensó para usarse como reloj continuo, y por tanto puede detenerse momentáneamente o tener pulsos espurios.
Otro posible problema es que las interfaces síncronas de fuente suelen conectarse a la FPGA a través de un conector físico; por ejemplo, cuando la fuente de datos es una cámara conectada a la placa principal mediante un cable. Aunque los conectores suelen ser fiables, basta la pérdida de contacto físico durante un nanosegundo, debida a vibraciones, para producir un pulso ilegal en la señal de reloj. Esto también puede ocurrir con las señales de datos, claro, pero suele tener menos importancia, sobre todo cuando la fuente de datos es una cámara. Sin embargo, cuando esa señal de reloj se conecta directamente a la lógica de usuario, un pulso de un nanosegundo puede armar un buen lío.
La mejor solución para interfaces síncronas de fuente con reloj y datos consiste, por tanto, en tratar tanto el reloj como los datos como señales normales. De acuerdo con ello, tanto el reloj síncrono de fuente como las señales de datos se someten a un muestreo (sampling) con flip-flops, empleando para ello un reloj bastante más rápido, estable y seguro. Preferiblemente, esto se hace con los flip-flops dedicados que están junto a los pines de E/S.
Cuando el reloj síncrono de fuente pasa de bajo a alto, eso se refleja en un cambio de la salida del flip-flop que muestrea esa señal. Por tanto, los flancos de subida del reloj síncrono de fuente pueden detectarse con lógica síncrona por el simple hecho de que la salida de ese flip-flop cambia de bajo a alto. Esa lógica se basa, por supuesto, en el reloj rápido y estable. Cuando esa lógica detecta un flanco de subida de este tipo, marca los datos como válidos. En otras palabras, las salidas de los flip-flops que contienen los valores de las entradas de datos se marcan como datos válidos.
La ventaja clara de este método de muestreo de señal 01 (01-signal sampling) es que pase lo que pase con la señal de reloj, la lógica de la FPGA sigue apoyándose en un reloj seguro. Si el reloj síncrono de fuente se vuelve loco, es responsabilidad de la lógica que detecta los flancos responder adecuadamente.
Esta técnica es posible para frecuencias relativamente bajas del reloj síncrono de fuente (normalmente hasta 200-300 MHz, según la velocidad de la FPGA, y si se usa muestreo DDR).
Para fuentes más rápidas, la solución preferida es alimentar una PLL con el reloj de la fuente y usar la salida de la PLL con la lógica de usuario. Como se ha dicho, la lógica debe ponerse en reset cuando la PLL indique que no está bloqueada. Probablemente es esta la solución correcta también por otra razón: cuando la frecuencia es demasiado alta para el muestreo de señal 01 que acabo de sugerir, lo más probable es que la única forma de garantizar un muestreo correcto sea encontrar la temporización mediante el desfase del reloj. Esto significa que la lógica ajusta la temporización automáticamente hasta que no se detectan errores en las señales muestreadas. Esta técnica requiere usar una PLL de todas formas.
Motivo #4: Violar las reglas del diseño RTL
El código Verilog (o VHDL) correcto para síntesis debe seguir unas reglas estrictas, en particular el paradigma RTL (Register Transfer Level). Entre otras cosas, esto significa que cualquier elemento de lógica que sea algún tipo de memoria (por ejemplo, un flip-flop) solo cambia de valor como consecuencia de un flanco de reloj. La única excepción es un reset asíncrono (asynchronous reset), que no puede ser una señal cualquiera.
Cuando un sintetizador (synthesizer) se encuentra con código Verilog que viola estas reglas, normalmente intenta ser complaciente y genera una lógica que puede no comportarse igual que la simulación. Otra posibilidad es que el resultado de la síntesis cumpla el comportamiento esperado la mayoría de las veces, pero falle aleatoriamente.
Por ejemplo, considera este diseño incorrecto de un contador entre 0 y 14:
reg [3:0] counter;
wire reset_cnt;
assign reset_cnt = (counter == 15); // This is so wrong!
always @(posedge clk or posedge reset_cnt)
if (reset_cnt)
counter <= 0;
else
counter <= counter + 1;
El error terrible está en usar @reset_cnt como reset asíncrono.
Pero empecemos explicando cómo funciona esto en la simulación: @counter cuenta en los flancos de subida de @clk. Pero cuando @counter alcanza el valor 15, @reset_cnt cambia a '1' y pone @counter a cero de forma asíncrona. Por tanto, cuando @counter se muestrea con @clk, muestra los valores de 0 a 14, como debe ser.
En el hardware puede que esto no funcione. El problema es que @reset_cnt se obtiene con lógica combinacional (combinatorial logic) a partir de @counter. Así que cuando @counter cambia de 7 a 8, la lógica que calcula @reset_cnt puede ver brevemente el valor de @counter como 15. Esto se debe a que 7 es 0111 en binario y 8 se codifica como 1000. Si el bit 3 es el que tiene el retardo de propagación (propagation delay) más corto hasta la lógica que calcula @reset_cnt, es posible que esa señal esté a '1' durante un instante. Como resultado, @counter a veces contará de 0 a 14 y otras veces contará de 0 a 7. La temperatura y otros factores ajenos pueden influir en cuál de las opciones se observa.
Sin embargo, esta explicación de por qué este ejemplo está mal está muy simplificada. Las herramientas son libres de implementar la lógica combinacional de las formas más creativas, así que prácticamente cualquier cosa puede ocurrir entre flancos de reloj. Lo único que garantizan las herramientas es que las señales son estables de acuerdo con los requisitos de temporización de los flip-flops de destino (tiempo de setup y tiempo de hold).
Así que, a menos que el diseño lógico siga estrictamente las reglas del diseño RTL, pueden pasar cosas raras sin ninguna duda.
Motivo #5: Temperatura y alimentación
Esta no es una causa habitual de problemas, y es fácil de comprobar. Aun así, la temperatura y las fuentes de alimentación pueden ser el origen de problemas raros.
Como es natural, si la temperatura del silicio está fuera del rango permitido, no se garantiza que nada funcione. Las causas más habituales son el sobrecalentamiento por una planificación térmica insuficiente o ventiladores que luchan contra el polvo.
En cuanto a las fuentes de alimentación, pueden producir una salida defectuosa por varios motivos. Una comprobación sencilla con un osciloscopio suele revelar si la tensión está dentro del rango especificado. Ten en cuenta, no obstante, que la tensión debe permanecer siempre dentro de ese rango. No basta con que la tensión media sea correcta: ni el ruido que crean siempre las fuentes conmutadas ni los picos ocasionales pueden sobrepasar los límites.
Ten en cuenta que, aunque un pico de no más de 1 μs pueda parecer inofensivo, dentro de la FPGA son decenas o cientos de ciclos de reloj, así que es un periodo significativo durante el cual la FPGA recibe una tensión incorrecta. Mejor mide la tensión en los condensadores de desacoplo cercanos a la FPGA para ver la tensión que realmente llega. Configura también el disparo (trigger) del osciloscopio en los límites superior e inferior de tensión, de modo que reaccione cuando se sobrepasen. No es fácil ver picos breves en la pantalla del osciloscopio, pero el disparo los atrapará.
A veces los problemas de alimentación son consecuencia directa de un mal diseño de la placa. Muchos módulos de alimentación tienen una corriente mínima que a menudo se pasa por alto. Si no se drena esa corriente mínima del módulo, este puede volverse inestable y generar una tensión que no cumple su especificación o, peor aún, puede tener oscilaciones ocasionales.
Otro error común es poner una fuente conmutada donde se necesita un regulador de tensión. En particular, hay osciladores de reloj de baja fluctuación de fase (jitter) que requieren una alimentación muy limpia. Si ese oscilador se alimenta con una fuente ruidosa, el ruido acaba convirtiéndose en fluctuación de fase en la salida del reloj. Si un transceptor Gigabit utiliza ese reloj (por ejemplo, PCIe, USB 3.x, fibra óptica, etc.), eso suele traducirse en un enlace de datos poco fiable.
Asimismo, cuando en el diseño hay memorias DDR, se necesita una fuente de tensión de referencia. Esa tensión la usan tanto la FPGA como las memorias DDR como umbral entre un '0' y un '1' en las líneas que van entre esos dos componentes. Si esa tensión la genera una fuente conmutada, lo más probable es que el ruido de la fuente dificulte, o incluso impida, transmitir datos sin errores entre la FPGA y las memorias DDR.
Motivo #6: ¿Estás de broma?
A veces, el motivo de la situación de magia negra es un fallo tan grande que uno se pregunta cómo pudo funcionar algo en absoluto. Por ejemplo, cuando la pista de la PCB está completamente desconectada del pin correspondiente de la FPGA y, aun así, la señal correcta llega a la FPGA gracias a la diafonía o a la capacidad parásita.
Esto suele ocurrir sobre todo con los relojes, porque a menudo están distribuidos por toda la placa, y el hecho de que sean señales periódicas aumenta las posibilidades de que lleguen a la FPGA lo bastante bien como para parecer correctos.
Así que, sin duda, coge un osciloscopio y comprueba todos los relojes lo más cerca posible de la FPGA. Si hay un condensador de acoplamiento de CA para el reloj, es un buen sitio para comprobar, sobre todo porque puedes descubrir que el condensador no está.
Motivo #7: Bugs a secas
O mejor dicho: el diseño nunca se hizo para funcionar. En ningún momento nadie se sentó a razonar cómo se garantizaba que la lógica hiciera su trabajo. En su lugar, el código se fue escribiendo poco a poco por prueba y error, en parte con simulaciones y en parte con hardware. El proceso se dio por terminado cuando las cosas parecían funcionar bien, pero al mirar el código parece un milagro que funcionara: como se ha parcheado tantas veces para arreglar esa pequeña cosa, es imposible seguir lo que ocurre, y mucho menos hacer cambios.
He puesto este motivo el último porque no es realmente un comportamiento de magia negra. Es solo un bug muy molesto. Sin embargo, es la causa más habitual de que los proyectos con FPGA se queden atascados.
Si todavía crees que es culpa de la FPGA
A veces no es culpa tuya. Puede haber un bug en la propia FPGA o en el software del fabricante. Esto ocurre con mucha menos frecuencia de lo que la gente suele culpar al fabricante de la FPGA, pero en raras ocasiones es cierto.
Por la tentación natural de culpar a otro, hazte un favor: no cierres la sesión de exorcismo echándole la culpa a la FPGA, a menos que tengas una de estas dos cosas, o ambas:
- Un registro de erratas del fabricante que coincida exactamente con tu situación: tanto en la causa del problema como en el resultado. Esto puede ser algo difícil de determinar, porque las erratas suelen estar redactadas a propósito de forma vaga, sobre todo para que el problema parezca extremadamente específico y raro, y para quitar importancia a las consecuencias. No te dejes tentar por interpretar un registro de erratas parecido como una coincidencia con tu caso. Siempre hay una errata que se parece de algún modo a tu caso.
- Una prueba incontestable: si puedes reproducir una y otra vez un bug concreto que explique exactamente por qué se produjo tu problema. No basta con demostrar que las herramientas o la propia FPGA se comportan de forma absurda. Tienes que acotarlo hasta un patrón lógico concreto y repetible que esté mal.
Si terminas sin ninguna de esas dos cosas y consigues apañar el problema de algún modo, hay bastantes probabilidades de que te lo vuelvas a encontrar más adelante.
El mejor ejemplo que tengo de un bug en la propia FPGA fue hace bastante tiempo, en la FIFO hardware de la Virtex-4 de Xilinx. Es decir, una FIFO de doble reloj cuya lógica de control estaba implementada directamente en silicio, no en el entramado lógico.
El flujo de datos a través de esa FIFO se atascaba de vez en cuando. Tras investigar un poco, resultó que la FIFO mantenía activas a la vez sus señales empty (vacío) y full (lleno), después de haber funcionado correctamente durante un tiempo. Esa es una condición ilegal, a menos que la FIFO esté en reset, y no lo estaba. Así que, después de asegurarme absolutamente de que estaba observando las señales correctas, cerré el caso con la conclusión de que había un bug en la FIFO de la FPGA. Y opté por FIFO implementadas en el entramado lógico.
Unos meses después encontré un registro de erratas sobre esas FIFO que no habría entendido de no haber conocido el problema de antemano. Pero después de leer la descripción con mucho cuidado, pude concluir que confirmaba mi observación.
Ese fue solo un ejemplo de lo evidente que debe ser un bug de la FPGA para que esté bien declarar que «no es culpa mía».
Resumen
Cuando parece que la FPGA desafía las leyes de la naturaleza, resulta tentador adoptar explicaciones que se apartan del sentido común. Sin embargo, es importante buscar una explicación racional, y con bastante frecuencia se puede encontrar sin necesidad de superpoderes.
Eso sí, buscar el motivo puede exigir una revisión a fondo del diseño, lo cual no tiene por qué ser malo. Por frustrante que pueda ser esa búsqueda, puede contribuir igualmente a mejorar la calidad del diseño.