Cómo analizar el informe de tiempo para Xilinx FPGA

Estoy tratando de aprender a programar FPGA, mi proyecto de prueba es una CPU MIPS canalizada de 5 etapas, que funciona.

Hasta ahora he estado optimizando para la utilización del área, sin embargo, esto ha causado una velocidad de reloj muy lenta (~50 MHz).

He estado mirando el informe de tiempo estático del mapa posterior generado por ISE, pero no puedo encontrarle mucho sentido. A continuación se muestra la sección para un solo camino (el más lento), no puedo entender por qué este camino sería tan lento.

Mis preguntas:

1) Si el retraso de tiempo es del 80 % de enrutamiento (como parece indicar este informe), ¿puedo mejorar esto? ¿Si es así, cómo?

2) ¿Cómo puedo reducir el componente lógico del tiempo?

3) Lo que se entiende por "origen" y "destino", en el siguiente ejemplo, opcode_out[1]es el origen y finished[0]el destino, sin embargo, en mi diseño, estos nunca están conectados directamente. Uno se establece en el borde negativo de la etapa de decodificación, el otro se establece en el borde positivo de la etapa de ejecución.

4) En algunos lugares he jugado usando asignaciones sin bloqueo, esto no es posible en todas partes. ¿Qué efectos de rendimiento tiene esto? He encontrado informes mixtos sobre esto.

5) Finalmente, ¿cuál es la probabilidad de que alcance la velocidad de mi reloj a 200 MHz, dado que actualmente está luchando por alcanzar los 50 MHz?

Paths for end point XLXI_30/XLXI_5/XLXI_3/execute_inst/finished_1 (OLOGIC_X2Y2.D1), 131 paths 
 -------------------------------------------------------------------------------- 
 Slack (setup path):     -6.906ns (requirement - (data path - clock path skew + uncertainty)) 
   Source:               XLXI_30/XLXI_5/XLXI_3/decode_inst/opcode_out_2 (FF) 
   Destination:          XLXI_30/XLXI_5/XLXI_3/execute_inst/finished_1 (FF) 
   Requirement:          5.000ns 
   Data Path Delay:      11.871ns (Levels of Logic = 6) 
   Clock Path Skew:      0.000ns 
   Source Clock:         XLXN_200 falling at 5.000ns 
   Destination Clock:    XLXN_200 rising at 10.000ns 
   Clock Uncertainty:    0.035ns 

   Clock Uncertainty:          0.035ns  ((TSJ^2 + TIJ^2)^1/2 + DJ) / 2 + PE 
     Total System Jitter (TSJ):  0.070ns 
     Total Input Jitter (TIJ):   0.000ns 
     Discrete Jitter (DJ):       0.000ns 
     Phase Error (PE):           0.000ns 

   Maximum Data Path at Slow Process Corner: XLXI_30/XLXI_5/XLXI_3/decode_inst/opcode_out_2 to XLXI_30/XLXI_5/XLXI_3/execute_inst/finished_1 
     Location             Delay type         Delay(ns)  Physical Resource 
                                                Logical Resource(s) 
     -------------------------------------------------  ------------------- 
     SLICE_X40Y70.DQ      Tcko                  0.408   XLXI_30/XLXI_5/XLXI_3/decode_inst/opcode_out<2> 
                                                XLXI_30/XLXI_5/XLXI_3/decode_inst/opcode_out_2 
     SLICE_X41Y70.D5      net (fanout=8)     e  0.759   XLXI_30/XLXI_5/XLXI_3/decode_inst/opcode_out<2> 
     SLICE_X41Y70.DMUX    Tilo                  0.313   XLXI_30/XLXI_5/XLXI_3/execute_inst/_n0402<5>1_FRB 
                                                XLXI_30/XLXI_5/XLXI_3/execute_inst/Mmux_func_in[5]_PWR_69_o_mux_83_OUT22_SW0 
     SLICE_X39Y70.B5      net (fanout=1)     e  0.377   N118 
     SLICE_X39Y70.B       Tilo                  0.259   XLXI_30/XLXI_5/XLXI_3/execute_inst/rd_value_out_wire<31> 
                                                XLXI_30/XLXI_5/XLXI_3/execute_inst/Mmux_func_in[5]_PWR_69_o_mux_83_OUT22 
     SLICE_X41Y72.A6      net (fanout=3)     e  0.520   XLXI_30/XLXI_5/XLXI_3/execute_inst/Mmux_func_in[5]_PWR_69_o_mux_83_OUT22 
     SLICE_X41Y72.A       Tilo                  0.259   XLXI_30/XLXI_5/XLXI_3/decode_inst/immediate_out<4> 
                                                XLXI_30/XLXI_5/XLXI_3/execute_inst/GND_74_o_GND_74_o_equal_146_o<5>1 
     SLICE_X41Y72.C5      net (fanout=19)    e  0.547   XLXI_30/XLXI_5/XLXI_3/execute_inst/GND_74_o_GND_74_o_equal_146_o<5>1 
     SLICE_X41Y72.C       Tilo                  0.259   XLXI_30/XLXI_5/XLXI_3/decode_inst/immediate_out<4> 
                                                XLXI_30/XLXI_5/XLXI_3/execute_inst/func_in[5]_PWR_69_o_equal_125_o<5>1 
     SLICE_X31Y70.A3      net (fanout=23)    e  0.934   XLXI_30/XLXI_5/XLXI_3/execute_inst/func_in[5]_PWR_69_o_equal_125_o 
     SLICE_X31Y70.A       Tilo                  0.259   XLXI_30/XLXI_5/XLXI_3/decode_inst/rd_out<3> 
                                                XLXI_30/XLXI_5/XLXI_3/execute_inst/_n0453 
     SLICE_X31Y70.B5      net (fanout=1)     e  0.359   XLXI_30/XLXI_5/XLXI_3/execute_inst/_n0453 
     SLICE_X31Y70.B       Tilo                  0.259   XLXI_30/XLXI_5/XLXI_3/decode_inst/rd_out<3> 
                                                XLXI_30/XLXI_5/XLXI_3/execute_inst/finished_glue_set 
     OLOGIC_X2Y2.D1       net (fanout=2)     e  5.556   XLXI_30/XLXI_5/XLXI_3/execute_inst/finished_glue_set 
     OLOGIC_X2Y2.CLK0     Todck                 0.803   XLXI_30/XLXI_5/XLXI_3/execute_inst/finished_1 
                                                XLXI_30/XLXI_5/XLXI_3/execute_inst/finished_1 
     -------------------------------------------------  --------------------------- 
     Total                                     11.871ns (2.819ns logic, 9.052ns route) 
                                                (23.7% logic, 76.3% route) 
No use el editor de esquemas. Vivimos en el siglo XXI...
Hacer un diseño complejo a 200 MHz va a ser difícil, puede hacerlo si canaliza sus datos, crea límites CLAROS entre bloques y módulos, reduce sus niveles lógicos a 4 o 5 y usa la opción de duplicación de registros y reprogramación de la herramienta de síntesis (ayuda un poco, pero no un factor 4 como quieres conseguir).

Respuestas (2)

1) El enrutamiento es siempre el factor dominante que limita el tiempo. Es por eso que un carry-lookahead no es realmente más rápido en FPGA, ya que el sumador más grande requiere más retrasos que superan en parte las ventajas. Su ruta tiene un nivel de lógica de 6, lo cual está bien. Sería muy difícil poner todas las rutas por debajo de 6. Sin embargo, algunas redes tienen un fanout alto, lo que produce demoras más largas. Puede intentar duplicar algunos registros para cortar el fanout o probar las opciones de Xilinx.

2) Al cambiar la ecuación lógica... El retraso en un segmento solo se ve afectado por el camino que toma, no por la operación lógica. Por supuesto, el camino que toma está dictado por la operación lógica. Sin embargo, puede ver en el informe de tiempo que tarda alrededor de 0,250 a 0,300 ns por segmento (más los retrasos de enrutamiento...).

3) Origen y destino son exactamente lo que dicen. Hay una ruta entre el código de operación y terminado. En el borde descendente de clk, el código de operación se vuelve válido y su nuevo valor se propaga en su circuito. La ruta termina en el registro terminado y la propagación debe estabilizarse antes del flanco ascendente de clk para cumplir con los tiempos.

4) No tiene influencia si los usas apropiadamente. Debería ser una opción de codificación para que el código sea más fácil de leer y comprender, pero los dos pueden describir el mismo circuito. Los problemas surgen cuando la gente los usa sin entender el impacto.

5) ¿Cuál es su FPGA? Si es la serie 7, será difícil pero posible, de lo contrario, de ninguna manera. Además, no aumente el reloj drásticamente. Cuando las restricciones son demasiado altas, Xilinx se asusta y los resultados no son confiables. Un diseño que funciona a 10 ns con una holgura de 1 ns puede fallar con -2 ns en un reloj de 11 ns. Hay un punto de quiebre en el que el sintetizador se esfuerza demasiado por cumplir con los tiempos y falla drásticamente al intentar colocar y enrutar el diseño más grande.

También te sugiero que elimines el reloj DDR. No hay ninguna razón para tener lógica DDR en un procesador, use un reloj dos veces más rápido en su lugar. Tener DDR agrega restricciones innecesarias sobre qué segmento puede contener qué lógica, y probablemente infle los retrasos de enrutamiento. Al usar un solo reloj, la ubicación usará (con suerte) el corte óptimo para todos los registros.

Cambiar a un reloj SDR desde un reloj DDR también eliminaría cualquier dependencia del ciclo de trabajo
Gracias por la respuesta detallada, un par de pequeñas preguntas/respuestas de seguimiento: estoy usando un Spartan 6, obtuve el tiempo de 23 ns a 16 ns al refactorizar el módulo de ejecución. Solo quedan unas 12 rutas que tienen una sincronización deficiente ahora, todas entre decodificación/ejecución y caché/caché. ¿Qué es "alto fanout"? Mencionas la duplicación de registros para arreglar esto, ¿puedes dar un ejemplo? ¿Qué sugiere que tengo un reloj DDR en el diseño? Lo hago, pero solo en la interfaz entre el FPGA y la memoria principal (es un requisito), no debería aparecer en absoluto en la "CPU".
En el informe, dice "Reloj de origen cayendo a 5 ns" y "Reloj de destino aumentando a 10 ns", definiendo así una ruta DDR. Un camino SDR solo tendría ascendente a ascendente. El abanico de una red es cuántas conexiones tiene esa red. Si su fanout es 20, puede duplicar el registro de conducción para obtener 2 veces un fanout de 10. Esto puede ser difícil de lograr ya que la herramienta a menudo elimina los registros duplicados o realiza la duplicación automáticamente. Al medir el tiempo, es importante saber si vale la pena, si 2 caminos son problemáticos, sí. Si 20 caminos son problemáticos, tendrá muchas más dificultades para mejorar.
Con respecto a DDR, ¿no significa simplemente que una restricción de tiempo está fallando entre un flanco descendente y ascendente, a diferencia de una restricción de tiempo que falla entre un flanco ascendente y descendente?
SDR no tiene rutas entre los bordes ascendente y descendente (y viceversa). SDR solo tiene rutas entre flancos ascendentes o descendentes sucesivos, por ejemplo, "Reloj de origen que aumenta a 0 ns" y "Reloj de destino que aumenta a 10 ns". Cada vez que vea subir o bajar o al revés, es un camino DDR.

Esta es solo una respuesta parcial, que amplía algunos de los puntos planteados por Jonathan Drolet.

3) Lo que se entiende por "origen" y "destino", en el siguiente ejemplo, opcode_out[1]es el origen y finished[0]el destino, sin embargo, en mi diseño, estos nunca están conectados directamente. Uno se establece en el borde negativo de la etapa de decodificación, el otro se establece en el borde positivo de la etapa de ejecución.

Cada señal en un diseño síncrono es generada por un flip-flop. Por lo tanto, la convención es etiquetar cada FF con la señal que genera. El analizador de tiempo comprueba cada par de FF para los que existe una ruta lógica entre ellos. Entonces, en este caso particular, se trata de la ruta desde la salida del FF que genera opcode_out[1]hasta la entrada del FF que genera finished[0].

Puede resultar confuso en diseños complejos, porque a veces la herramienta de síntesis replicará FF o lógica para solucionar problemas de fanout, y esto crea señales con nombres que no coinciden exactamente con los nombres en el código fuente. A medida que profundices en esto, verás lo que quiero decir.

4) En algunos lugares he jugado usando asignaciones sin bloqueo, esto no es posible en todas partes. ¿Qué efectos de rendimiento tiene esto? He encontrado informes mixtos sobre esto.

El tipo de asignación no tiene ningún efecto sobre la temporización de la lógica sintetizada, que solo depende de cómo se activan las asignaciones por eventos como los bordes del reloj. Sin embargo, el tipo de asignación puede cambiar la funcionalidad del código, así que asegúrese de que esté haciendo lo que desea en todos los casos.

5) Finalmente, ¿cuál es la probabilidad de que alcance la velocidad de mi reloj a 200 MHz, dado que actualmente está luchando por alcanzar los 50 MHz?

La única forma de obtener una aceleración de 4x es rediseñar cuidadosamente su implementación, utilizando muchas más etapas de canalización y usando mucha menos lógica por etapa.

En el ejemplo que muestra, tiene seis niveles de lógica en la ruta que se analiza. Es posible que deba limitar eso a dos o tres niveles de lógica por ruta, pero esto tiene implicaciones importantes sobre cómo funciona el diseño en general. Una vez tuve que implementar un sumador binario largo para que no tuviera más de 3 niveles de lógica por etapa de canalización. Es factible, pero realmente necesitas prestar atención a los detalles.

Gracias por la respuesta. Hice algunos cambios y ahora mi diseño es más rápido (de 23 ns a 16 ns). El nuevo "camino más lento" tiene 12 niveles lógicos, así que supongo que sé dónde debo centrar mi atención.