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)
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.
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 yfinished[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.
FRob
FarhadA