Cómo obtener un diseño de FPGA que definitivamente funcione en hardware real

Acabo de empezar a aprender diseño de lógica digital con FPGA y he estado construyendo muchos proyectos. La mayoría de las veces (ya que soy un poco novato), tengo un diseño que simula perfectamente (simulación de comportamiento) pero no sintetiza correctamente.

Entonces, mi pregunta es "¿cuáles son los pasos de diseño que puedo incorporar en mi flujo de trabajo, que asegurarán que tengo un diseño funcional que funcionará correctamente en mi FPGA?"

Tengo dos áreas principales en las que espero asesoramiento, pero esto se basa absolutamente en un punto de vista mío muy limitado como principiante, y más son bienvenidos:

  • Todos los pasos (ver el esquema RTL, simulación posterior a la síntesis, ...) debo emprender el aprendizaje para la mejor práctica.
  • Qué debo tener en cuenta al diseñar mi lógica (por ejemplo, FSM o circuitos secuenciales) para evitar resultados inesperados.

Estoy usando un Xilinx Spartan 6 FPGA y Xilinx ISE Design suite para mi trabajo.

¿Qué tipo de problemas te encuentras con la síntesis? ¿Consigue un alto nivel de cobertura en la simulación?
@ pjc50 No entiendo la pregunta. ¿Qué quiere decir con "alto nivel de cobertura en simulación"?
Tiene un banco de pruebas o un estímulo que impulsa la simulación. Las herramientas de cobertura le indican cuánto del diseño está realmente ejercitado por la prueba, como porcentaje. Si este número es demasiado bajo, entonces su banco de pruebas es inadecuado y no está probando algunos casos que podrían surgir en el uso real.
@ pjc50 ese es realmente un muy buen consejo. ¿Cuál es el equivalente de esto en la suite de diseño Xilinx ISE?
Una búsqueda rápida en Google sugiere que esto realmente falta en ISIM y debe usar Modelsim u otras herramientas de terceros. Estoy más familiarizado con la ruta de Altera (que usa Modelsim).
El primer paso si está utilizando ISIM es activar las malditas comprobaciones de rango. Nadie sabe por qué están apagados de forma predeterminada, pero a este tipo le costó horas . electronics.stackexchange.com/questions/153362/…
Vale la pena señalar: sintetiza y "definitivamente funciona en hardware real" son diferentes niveles de rigor. Hay patrones que uno puede seguir para asegurarse de que se sintetice. Sin embargo, cuando se trata de hacerlo funcionar en hardware real, con certeza, se debe recordar la máxima de la simulación: "Todos los modelos están equivocados; algunos son útiles".
En los comentarios sobre su pregunta anterior, compartió su código. No veo ninguna razón por la que este código no pueda sintetizarse. Pero nunca mencionaste limitaciones. ¿Proporcionó un archivo de restricciones que especifica correctamente la sincronización del reloj? Incluso una simple restricción de período de reloj debería ser adecuada para su diseño.
@ThePhoton el problema fue con las restricciones, para el pin que estaba usando como entrada, no habilité el pullup ni conecté un pullup externo. Por eso no funcionó. Después de hacer el cambio, el diseño se ejecutó sin problemas.

Respuestas (5)

En un lugar donde trabajé había dos campamentos de diseñadores de FPGA. Un campo que llamé simular, simular, simular o s cubed. El otro campo tenía que ver con el diseño.

Los muchachos de s cubed usaron un simulador como modelsim, crearon un diseño inicial a través de métodos de codificación y/o bloques en la suite de diseño. Luego lo simularían y encontrarían las cosas que no funcionarían, luego cambiarían el código. Este proceso se repitió varias veces hasta que dieron con un diseño que funcionó.

El campamento de diseño (que preferí) diseñaría la forma de onda en papel (o papel digital como visio), exactamente lo que se requería. Luego crea un diagrama lógico. Este es un proceso de autodocumentación. Luego, el diagrama se tradujo a código (el código y el diagrama eran 1:1 si había algo en el diagrama, había un proceso para ello en el código). Luego se simuló y la forma de onda de simulación se comparó con la forma de onda diseñada en papel, y se esperaba que fuera la misma.

Terminé haciendo ambas cosas, a veces entraba en modo s cubed y no era muy divertido. Descubrí que a veces perdía de vista mi objetivo. Por ejemplo, cambiaría un estado en una máquina de estado y el cambio se extendería al siguiente estado, luego tendría que arreglar eso. Terminé pasando más tiempo que pensando en ello.

¿En qué campamento preferirías estar? Creo que debe haber un diseño riguroso, hacer lo que funcione para ti, pero creo que cuanto más detallado y riguroso seas en el diseño, menos problemas tendrás a largo plazo. Di algunos ejemplos de lo que es posible, es posible que no se ajusten a la estructura organizativa de su lugar de trabajo. La razón por la cual los detalles del diseño y la planificación cuidadosa son tan útiles es que te obligan a pensar en lo que estás haciendo. Facilita la depuración. Desarrolle un flujo de trabajo de diseño que permita que esto suceda. Además, familiarícese con las herramientas de simulación y escriba buenos bancos de prueba que evalúen todas las condiciones que podría experimentar el dispositivo simulado. Por supuesto, esto debe equilibrarse con el tiempo. Por ejemplo, escriba el código ADC HDL que simulará el dispositivo en sus simulaciones.

La herramienta más valiosa para tener en el diseño de FPGA (en mi opinión) es un buen procedimiento de prueba que le permitirá probar completamente su diseño y ejecutarlo a través de sus pasos. No se puede esperar que un diseño de FPGA "simplemente funcione", se necesita esfuerzo para asegurarse de que todas las piezas funcionen. Si detecta errores, vuelva a la simulación y el diseño y aprenda cuáles son las diferencias entre un FPGA simulado y un RTL. Eso viene principalmente con la experiencia, pero si el diseño funciona en simulación pero no en hardware, entonces necesita averiguar por qué hay una diferencia.

Algunas cosas clave que aprendí:
1) Desinfecte sus entradas, el reloj y los circuitos de reinicio deben estar limpios o puede hacer que la metaestabilidad se propague a través de su sistema. Sepa qué es un sincronizador de rango dual. Hay muchas topologías diferentes para los circuitos de reinicio, sepa cómo usarlos (hay un gran artículo en la web, aunque no lo tengo a mano).
2) Obtenga los requisitos del diseño por adelantado y luego diseñe alrededor de ellos. Si las personas que te rodean no te dan requisitos definidos, entonces crea algunos por tu cuenta.
3) La caja de herramientas de punto fijo de Matlab es excelente para simular sistemas de control y aplicaciones DSP, pero es posible que no tenga acceso a eso. Es una excelente manera de probar un diseño antes de codificar.
4) El diseño es lo primero, luego la codificación y luego la simulación.
5) Estrictamente tipificado, también mantenga los nombres de las señales consistentes en el esquema de pcb y hdl. (Esta es también la razón por la que prefiero VHDL a verilog.

+1 para "s al cubo" o s i metro tu yo a t i o norte 3
Bastante bien: a "diseño riguroso" agregaría "usando el sistema de tipos". Ejemplo: un índice de matriz del tipo apropiado, como el rango de la matriz, sin necesidad de probar la condición fuera de los límites. Solo estaría en desacuerdo con "la forma de onda comparada con la forma de onda diseñada en papel"... la forma de onda diseñada debe estar en VHDL en esa etapa (o tal vez leer desde un archivo de texto) y el simulador debe realizar la comparación.
También se podría hacer de esa manera, me resultó útil diseñar una forma de onda en papel porque me dio algo con lo que comparar. Al igual que una forma de onda ADC, la sincronización se diseñó y luego se comparó con la salida de modlesim y luego se verificó físicamente. Si la salida del modelo es correcta, compárela con eso. El código estaba fuertemente tipeado (olvidé mencionarlo), pero eso es realmente importante. Es por eso que prefiero mucho más VHDL sobre Verilog, hay menos atajos que puede tomar. Y hace que el código sea mucho más legible.
si. En realidad, al igual que otras áreas, como el software o el hardware convencional, el punto de partida es dividir el problema en bloques y luego preguntarse "¿cómo sabré cuándo funciona ese bloque?". Entonces hacerlo. Construya su diseño bloque por bloque, luego junte los bloques y vuelva a probar que lo que obtiene es lo que se espera. A veces, puede darse cuenta de que con un mejor diseño a nivel de bloque sería más limpio o más fácil, por lo que retrocede.

Las cosas principales son:

  • Codificación cuidadosa para evitar estructuras no sintetizables
  • Minimice los niveles lógicos para un mejor rendimiento de tiempo (haga que la lógica entre registros sea lo más simple posible)
  • probar, probar, probar para garantizar la corrección funcional y verificar cosas como registros no inicializados y cables desconectados
  • síntesis y verifique los registros de síntesis en busca de advertencias, asegúrese de que las advertencias no indiquen problemas (es decir, la advertencia de registro eliminado podría ser intencional (no usó una salida de módulo) o no intencional (olvidó conectar la salida del módulo/error tipográfico/etc.))
  • mapeo y verifique el informe del mapa para las cifras de utilización, asegúrese de que el FPGA no esté demasiado lleno
  • lugar y ruta y análisis de tiempo, asegúrese de que su diseño se ejecutará a la velocidad de reloj requerida

He tenido varios diseños bastante complejos que funcionan correctamente (o al menos en su mayoría correctamente) en la primera prueba en un FPGA real siguiendo lo anterior. No es necesario verificar el esquema RTL, eso es extremadamente engorroso y una completa pérdida de tiempo para diseños grandes. Una simulación posterior a la síntesis sería mucho más útil.

Gracias por su rápida respuesta. ¿Podría dar más detalles sobre el segundo punto (minimizar los niveles lógicos)?

Todo su código sintetizable debe poder expresarse como:

  • LUT
  • Chancletas
  • Primitivas específicas del proveedor

Las primitivas específicas del proveedor se instancian explícitamente, o se generan mediante el asistente del proveedor, o se infieren mediante patrones de codificación muy específicos, por lo que no debería haber ninguna ambigüedad allí.

En VHDL, por ejemplo, no se puede usar wait foren código sintetizable. Para entender por qué, intente expresar de manera determinista wait for 100 nsusando LUT o flip-flops. no puedes

Eso no significa que no pueda implementarlo configurando un contador con una frecuencia de reloj conocida (con un período que puede dividir 100 ns) y usar su conteo para saber cuándo se acabó el tiempo. Pero el motor de síntesis no generará este esquema automáticamente, debe ser explícito acerca de la arquitectura en términos de lógica combinacional (compuertas/LUT) y registros.

Entonces, lo principal a tener en cuenta para generar código sintetizable es tener una imagen relativamente clara de cómo su código se convierte en puertas lógicas y flip flops. Eso es realmente.

wait until rising_edge(clk);es ciertamente sintetizable, aunque algunas herramientas imponen restricciones en su uso.

El primer paso más obvio es verificar las advertencias.

Las herramientas de Xilinx producen archivos de registro que advierten sobre cualquier cosa que no sea la intención del codificador. A veces esto es molesto, cuando tienes montones de advertencias sobre señales no utilizadas que sabes perfectamente que no se utilizan. Pero a veces detecta errores genuinos. Si eres un novato, las posibilidades de que cometas un error son significativamente mayores.

Luego, debe configurar las restricciones de tiempo. ¿Con qué rapidez después de un flanco ascendente en el reloj A se debe configurar la línea de datos B? ¿O cuánto tiempo debe mantenerse la línea de datos B antes de un flanco descendente en el reloj A? Las restricciones de tiempo le permitirán especificar todo esto. Si no tiene restricciones de tiempo, el compilador puede suponer que no le importa especialmente y podría enrutar sus señales a cualquier parte. Si tiene restricciones de tiempo, el compilador trabajará para asegurarse de que sus señales cumplan con esas restricciones cambiando la ubicación. Y si no puede cumplir con las restricciones de tiempo, mostrará una advertencia.

Si su problema es que las salidas no están haciendo lo que esperaba, mire en detalle los bloques de E/S. Cada pin de E/S tiene un poco de lógica asociada y un flip-flop. Es posible que el orden en el que especifica su lógica y las variables de estado en su código no haga posible que su código se ajuste a esta arquitectura, por lo que obtiene un retraso adicional desde donde sea que se coloque. Las advertencias sobre las restricciones de tiempo le dirán si esto sucede (suponiendo que haya configurado sus restricciones de tiempo), pero solucionarlo requiere que comprenda el hardware y cómo su diseño se mapeará en el hardware. En general, esto solo es un problema cuando comienzas a alcanzar velocidades de reloj altas, pero vale la pena mencionarlo.

No me especialicé en diseño de circuitos integrados; sin embargo, mi primer trabajo después de graduarme fue diseñar módulos digitales en una empresa de diseño de MCU. Ni siquiera tenía conocimiento sobre verilog entonces.

En mi experiencia, lo más importante es pensar en forma de hardware. Lea varios módulos hdl de la industria y, si es posible, verifique el esquema correspondiente con la ayuda de las herramientas EDA. Aprenda y recuerde algunos componentes básicos, como detección de bordes/codificación gris/controlador FIFO/FSM, etc. El código sintetizable es un subconjunto de todo el estándar. Para propósitos de un diseño robusto/libre de errores, la estructura del lenguaje en uso real en una empresa es además un subconjunto de código sintetizable. Así que no necesitas mucha estructura de lenguaje.

Un circuito es una interconexión entre diferentes bloques que realizan funciones específicas, y ese bloque en sí mismo puede dividirse aún más en la interconexión de elementos más detallados. Entonces, para comenzar a diseñar, use los bloques fundamentales para diseñar el circuito usando un lápiz o una herramienta de dibujo esquemático o en su mente, lo que sea, examínelo. Y escriba el código hdl para describir su diseño en formato ASCII.