01signal.com

Quartus: Empaquetado de registros en las celdas de entrada/salida

A menudo prefiero gestionar los tiempos de entrada/salida asegurándome de que todos los registros se colocan en las celdas de E/S. Es decir, donde los tiempos importan.

Parece que Quartus no empaqueta los registros en las celdas de E/S por defecto. En fin, aquí va la receta fácil para este caso.

En una versión anterior de este post sugerí deshabilitar la comprobación de tiempos en todas las E/S. Eso silencia el aviso de camino sin restricciones (unconstrained path) durante la implementación y, en particular, evita que la sección «TimeQuest Timing Analyzer» del panel de informes de Quartus se ponga en rojo:

set_false_path -from [get_ports]
set_false_path -to [get_ports]

Resulta que no es una idea tan buena, sobre todo en lo que respecta a los puertos de entrada. Esto se explica más abajo.

Sin embargo, hay que convencer al colocador (fitter) de que ponga los registros en el bloque de E/S. En el QSF hay que añadir:

set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to *
set_instance_assignment -name FAST_INPUT_REGISTER ON -to *
set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to *

Es un poco agresivo aplicar estas asignaciones a absolutamente todos los registros, pero cumple su función. El colocador (fitter) emite avisos para los elementos de E/S en los que no consigue imponer estas restricciones, lo cual no está nada mal.

Para ver cómo ha ido, mira la «Resource Section» del informe del colocador (puedes encontrarlo en el panel de informes de Quartus) y busca «Input Registers» o lo que corresponda.

La diferencia se ve clara en los informes de tiempos de los caminos (paths) que involucran celdas de E/S. Por ejemplo, compara este camino, que involucra un registro de E/S:

+----------------------------------------------------------------------------------+
; Data Arrival Path                                                                ;
+---------+---------+----+------+--------+-----------------------+-----------------+
; Total   ; Incr    ; RF ; Type ; Fanout ; Location              ; Element         ;
+---------+---------+----+------+--------+-----------------------+-----------------+
; 2.918   ; 2.918   ;    ;      ;        ;                       ; data path       ;
;   0.000 ;   0.000 ;    ;      ; 1      ; DDIOOUTCELL_X3_Y0_N32 ; rst             ;
;   0.465 ;   0.465 ; RR ; CELL ; 1      ; DDIOOUTCELL_X3_Y0_N32 ; rst|q           ;
;   0.465 ;   0.000 ; RR ; IC   ; 1      ; IOOBUF_X3_Y0_N30      ; RESETB~output|i ;
;   2.918 ;   2.453 ; RR ; CELL ; 1      ; IOOBUF_X3_Y0_N30      ; RESETB~output|o ;
;   2.918 ;   0.000 ; RR ; CELL ; 0      ; PIN_P3                ; RESETB          ;
+---------+---------+----+------+--------+-----------------------+-----------------+

Observa el elemento DDIOOUTCELL y el incremento cero en el enrutado entre el registro y el IOOBUF.

Para comparar, aquí hay un camino en el que no se aplicó un registro de E/S (porque la lógica lo impidió):

+--------------------------------------------------------------------------------+
; Data Arrival Path                                                              ;
+---------+---------+----+------+--------+-----------------+---------------------+
; Total   ; Incr    ; RF ; Type ; Fanout ; Location        ; Element             ;
+---------+---------+----+------+--------+-----------------+---------------------+
; 8.284   ; 8.284   ;    ;      ;        ;                 ; data path           ;
;   0.000 ;   0.000 ;    ;      ; 1      ; FF_X3_Y0_N17    ; Dir_flop_sig        ;
;   0.496 ;   0.496 ; RR ; CELL ; 8      ; FF_X3_Y0_N17    ; Dir_flop_sig|q      ;
;   2.153 ;   1.657 ; RR ; IC   ; 1      ; IOOBUF_X3_Y0_N9 ; DATA[7]~output|oe   ;
;   8.284 ;   6.131 ; RF ; CELL ; 1      ; IOOBUF_X3_Y0_N9 ; DATA[7]~output|o    ;
;   8.284 ;   0.000 ; FF ; CELL ; 1      ; PIN_T3          ; DATA[7]             ;
+---------+---------+----+------+--------+-----------------+---------------------+

Aquí vemos cómo un biestable de propósito general genera la señal, lo que da lugar a un retardo de enrutado de 1,657 ns. El problema principal es que ese retardo de enrutado será distinto en cada implementación; así que, si la placa tiene algún problema de integridad de señal, puede que se eche la culpa a la FPGA, porque distintas versiones del diseño de la FPGA parecerán arreglar el problema o hacerlo reaparecer.

Restricciones de tiempos

Tanto los puertos de entrada como los de salida deberían tener unas restricciones de tiempos (timing constraints) ajustadas, de modo que no puedan cumplirse si no se aprovechan al máximo los registros de E/S. Con esto no solo se provoca un fallo de tiempos si algo sale mal con el empaquetado de registros deseado, sino que además es necesario para conseguir el retardo mínimo entre la entrada y el registro, como se explica a continuación.

Lo que sigue solo se aplica cuando el reloj que excita los registros está directamente relacionado con un reloj externo (por ejemplo, con un PLL que multiplica la frecuencia por un número entero). Si el reloj de los registros no tiene relación práctica con el reloj externo, el asunto se complica bastante, como se explica en este post.

Para demostrar este asunto, considera el siguiente código Verilog:

module top
  (
   input        clk,
   input        in,
   output reg   out
   );

   reg 		in_d, in_d2;
   wire  	pll_clk;

   always @(posedge pll_clk)
     begin
	in_d <= in;
	in_d2 <= in_d;
	out <= in_d2;
     end

  /* Here comes an instantiation of a phase-compensating PLL, which
     doesn't change the frequency */
endmodule

Considera también la siguiente restricción en el archivo SDC:

create_clock -name main_clk -period 10 -waveform { 0 5 } [get_ports {clk}]

derive_pll_clocks
derive_clock_uncertainty

set_input_delay -clock main_clk -max 8.5 [get_ports in*]
set_input_delay -clock main_clk -min 0 [get_ports in*]

Como se explica en este post, set_input_delay es el retardo máximo de la fuente de la señal, desde el reloj hasta que alcanza un estado lógico válido. Como el período del reloj se ha fijado en 10 ns, poner la restricción de retardo en 8,5 ns deja 1,5 ns hasta que llegue el siguiente flanco (en 10 ns). En otras palabras, el tiempo de preparación (setup time) en el pin de la FPGA queda limitado a no más de 1,5 ns.

Observa que set_max_delay también se puede usar para este fin (en algunos casos es la única manera), como se comenta en este post.

Una compilación de todo esto (junto con la asignación FAST_INPUT_REGISTER ON del QSF que se ha mostrado antes) produce el siguiente segmento en el informe de tiempos:

+----------------------------------------------------------------------------------+
; Data Arrival Path                                                                ;
+---------+---------+----+------+--------+-------------------+---------------------+
; Total   ; Incr    ; RF ; Type ; Fanout ; Location          ; Element             ;
+---------+---------+----+------+--------+-------------------+---------------------+
; 0.000   ; 0.000   ;    ;      ;        ;                   ; launch edge time    ;
; 0.000   ; 0.000   ;    ;      ;        ;                   ; clock path          ;
;   0.000 ;   0.000 ; R  ;      ;        ;                   ; clock network delay ;
; 8.500   ; 8.500   ; F  ; iExt ; 1      ; PIN_F2            ; in                  ;
; 9.550   ; 1.050   ;    ;      ;        ;                   ; data path           ;
;   8.500 ;   0.000 ; FF ; IC   ; 1      ; IOIBUF_X0_Y22_N15 ; in~input|i          ;
;   9.308 ;   0.808 ; FF ; CELL ; 1      ; IOIBUF_X0_Y22_N15 ; in~input|o          ;
;   9.308 ;   0.000 ; FF ; IC   ; 1      ; FF_X0_Y22_N17     ; in_d|d              ;
;   9.550 ;   0.242 ; FF ; CELL ; 1      ; FF_X0_Y22_N17     ; in_d                ;
+---------+---------+----+------+--------+-------------------+---------------------+

Al contrario que en el caso del registro de salida, no aparece ningún biestable del tipo «DDIOINCELL» en la lista; en su lugar hay algo que parece un biestable normal. Sin embargo, observa que el cableado hacia ese biestable tiene retardo cero (marcado en rojo), lo que indica claramente que el biestable y el buffer de entrada están integrados en el mismo elemento.

El informe de la hoja de datos (datasheet report) para esta entrada dice:

+---------------------------------------------------------------------------------------------------+
; Setup Times                                                                                       ;
+-----------+------------+-------+-------+------------+---------------------------------------------+
; Data Port ; Clock Port ; Rise  ; Fall  ; Clock Edge ; Clock Reference                             ;
+-----------+------------+-------+-------+------------+---------------------------------------------+
; in        ; main_clk   ; 1.282 ; 1.461 ; Rise       ; altpll_component|auto_generated|pll1|clk[0] ;
+-----------+------------+-------+-------+------------+---------------------------------------------+

+-----------------------------------------------------------------------------------------------------+
; Hold Times                                                                                          ;
+-----------+------------+--------+--------+------------+---------------------------------------------+
; Data Port ; Clock Port ; Rise   ; Fall   ; Clock Edge ; Clock Reference                             ;
+-----------+------------+--------+--------+------------+---------------------------------------------+
; in        ; main_clk   ; -0.683 ; -0.862 ; Rise       ; altpll_component|auto_generated|pll1|clk[0] ;
+-----------+------------+--------+--------+------------+---------------------------------------------+

Como es debido, el tiempo de preparación (setup time) que exige la FPGA es inferior al límite de 1,5 ns impuesto por la restricción.

Ahora aflojemos el retardo de preparación de entrada en 2 ns, dejando todo lo demás igual, y volvamos a compilar:

set_input_delay -clock main_clk -max 6.5 [get_ports in*]
set_input_delay -clock main_clk -min 0 [get_ports in*]

El segmento del informe de tiempos ahora dice:

+----------------------------------------------------------------------------------+
; Data Arrival Path                                                                ;
+---------+---------+----+------+--------+-------------------+---------------------+
; Total   ; Incr    ; RF ; Type ; Fanout ; Location          ; Element             ;
+---------+---------+----+------+--------+-------------------+---------------------+
; 0.000   ; 0.000   ;    ;      ;        ;                   ; launch edge time    ;
; 0.000   ; 0.000   ;    ;      ;        ;                   ; clock path          ;
;   0.000 ;   0.000 ; R  ;      ;        ;                   ; clock network delay ;
; 6.500   ; 6.500   ; F  ; iExt ; 1      ; PIN_F2            ; in                  ;
; 8.612   ; 2.112   ;    ;      ;        ;                   ; data path           ;
;   6.500 ;   0.000 ; FF ; IC   ; 1      ; IOIBUF_X0_Y22_N15 ; in~input|i          ;
;   7.308 ;   0.808 ; FF ; CELL ; 1      ; IOIBUF_X0_Y22_N15 ; in~input|o          ;
;   8.370 ;   1.062 ; FF ; IC   ; 1      ; FF_X0_Y22_N17     ; in_d|d              ;
;   8.612 ;   0.242 ; FF ; CELL ; 1      ; FF_X0_Y22_N17     ; in_d                ;
+---------+---------+----+------+--------+-------------------+---------------------+

¿Cómo? ¿El retardo de interconexión ha subido de repente a 1,062 ns? Fíjate en que la ubicación del registro no ha cambiado, así que no cabe duda de que in_d es un registro de E/S. Entonces, ¿de dónde ha salido este retardo?

Para responder a esto hace falta examinar el diseño con más detalle. Después de una compilación completa y de elegir Tools > Netlist Viewers > Technology Map Viewer (Post-Fitting), aparece el siguiente diagrama (se muestra parcialmente abajo; haz clic para ampliar):

Design diagram

Al hacer clic con el botón derecho sobre in_d (el registro) y elegir Locate Node > Locate in Resource Property Editor se obtiene lo siguiente (haz clic para ampliar):

Property editor view

En la parte derecha de ese dibujo (no se muestra arriba), la propiedad «Input Pin to Input Register Delay» está ajustada a 2. Esa es la razón del retardo. Antes de aflojar la restricción estaba a 0. La lección inmediata es:

Si la restricción de setup no se ajusta al mejor valor que la tecnología permite, Quartus puede añadir un retardo a costa de ese margen.

¿Pero por qué, Quartus, por qué?

Entonces uno se preguntará por qué Quartus mete este retardo entre el pad de entrada y el registro. ¿No era precisamente para muestrear cuanto antes? Para responder, veamos el informe de hoja de datos (datasheet report) actualizado:

---------------------+
; Data Port ; Clock Port ; Rise  ; Fall  ; Clock Edge ; Clock Reference                             ;
+-----------+------------+-------+-------+------------+---------------------------------------------+
; in        ; main_clk   ; 2.205 ; 2.523 ; Rise       ; altpll_component|auto_generated|pll1|clk[0] ;
+-----------+------------+-------+-------+------------+---------------------------------------------+

+-----------------------------------------------------------------------------------------------------+
; Hold Times                                                                                          ;
+-----------+------------+--------+--------+------------+---------------------------------------------+
; Data Port ; Clock Port ; Rise   ; Fall   ; Clock Edge ; Clock Reference                             ;
+-----------+------------+--------+--------+------------+---------------------------------------------+
; in        ; main_clk   ; -1.570 ; -1.882 ; Rise       ; altpll_component|auto_generated|pll1|clk[0] ;
+-----------+------------+--------+--------+------------+---------------------------------------------+

Recuerda que se quitaron 2 ns de la restricción de retardo. Por tanto, el tiempo de preparación (setup time) máximo permitido pasó de 1,5 ns a 3,5 ns. Es fácil ver que se cumple este requisito, con un margen (slack) de casi 1 ns.

Vamos, que Quartus dijo algo así como: «Puedo cumplir el requisito de setup sin problemas, con un excedente de 2 ns. Voy a dar 1 ns extra al tiempo de preparación y 1 ns al requisito de retención (hold time), que es 0 ns». Y efectivamente, al añadir 1,062 ns con este retardo, el tiempo de retención mejoró de -0,683 ns a -1,570 ns (y no me machaquéis por que la diferencia no sea exacta).

En resumen: Quartus ha ampliado el margen tanto de setup como de hold, haciendo la entrada más robusta frente a la fluctuación de fase (jitter). Aunque es algo bastante sensato, a menudo no es lo que uno quiere ni espera que ocurra.

Conclusión: si quieres conseguir el retardo absolutamente mínimo entre la entrada y el registro, haz una compilación con una restricción de retardo que falle, y luego afloja la restricción lo justo para resolver ese fallo. Así te aseguras de que Quartus no intente «mejorar» los tiempos añadiendo ese retardo de entrada para conseguir un mejor tiempo de retención.

Usando primitivas DDR

Las FPGA de Intel tienen lógica dentro o cerca de las celdas de E/S destinada a permitir generar la salida y muestrear la entrada al doble de la frecuencia del reloj. Este tema se trata en detalle en la guía de usuario correspondiente, ug_altddio.pdf. Instanciar una primitiva DDR (primitive) (o usar la megafunción ALTDDIO_BIDIR) parece un recurso atractivo para obligar a las herramientas a poner los registros en las celdas de E/S. Sin embargo, no tiene por qué ser una buena idea.

Por ejemplo, una instanciación (instantiation) como esta:

altddio_bidir ioddr
 (
 .padio(pin),
 .aclr (1'b0),
 .datain_h(datain_h),
 .datain_l(datain_l),
 .inclock(clk),
 .oe(oe),
 .outclock(clk),
 .dataout_h(dataout_h),
 .dataout_l(dataout_l),
 .oe_out (),
 .aset (1'b0),
 .combout(),
 .dqsundelayedout(),
 .inclocken(1'b1),
 .outclocken(1'b1),
 .sclr(1'b0),
 .sset(1'b0));
 defparam
   ioddr.extend_oe_disable = "OFF",
   ioddr.implement_input_in_lcell = "OFF",
   ioddr.intended_device_family = "Cyclone IV E",
   ioddr.invert_output = "OFF",
   ioddr.lpm_hint = "UNUSED",
   ioddr.lpm_type = "altddio_bidir",
   ioddr.oe_reg = "REGISTERED",
   ioddr.power_up_high = "OFF",
   ioddr.width = 1;

Esto, efectivamente, produce una lógica que implementa una interfaz DDR bidireccional, pero con un éxito parcial en lo que a los tiempos se refiere, al menos en Cyclone IV. El tiempo de reloj a salida (clock-to-output) es exactamente el mismo que con un registro de salida normal empaquetado en la celda de E/S, pero el retardo del camino de entrada es en realidad peor con la instanciación anterior. Los resultados pueden ser distintos en otras familias de FPGA de Intel.

Observa que, para imitar registros SDR normales con una primitiva DDR, sus puertos datain_h y datain_l deben estar conectados al mismo hilo, de modo que el flanco de bajada del reloj no cambie nada. Del mismo modo, el valor del puerto dataout_l debe ignorarse, porque se muestrea en el flanco de bajada. Ten en cuenta también que el puerto de habilitación de salida (oe) es una entrada SDR: hasta donde yo sé, no es posible activar y desactivar el estado de alta impedancia (high-Z) al ritmo de DDR con las FPGA de Intel. Al menos no con las primitivas lógicas que proporcionan.

Ahora, sobre por qué funcionó bien con los registros de salida y no con los de entrada: la pista está en los informes de tiempos de arriba. Incluso para un registro normal de celda de E/S se usa un componente DDIOOUTCELL_Xn_Ym_Nk como registro. Dicho de otra forma, el registro de salida DDR se usa incluso para salidas a un solo ritmo, pero solamente con un flanco de reloj. En cuanto al camino de entrada, los informes de tiempos de arriba muestran que se usa un registro de la trama de lógica (logic fabric), del tipo FF_Xn_Ym_Nk. Y aquí está el quid: la lógica de entrada DDR también se implementa en la trama de lógica. Y para colmo, en el caso de DDR se intercalan bloques de lógica combinacional (combinatorial logic) entre la celda de E/S y el biestable. Francamente, no entiendo por qué, porque cada uno de esos bloques combinacionales no es más que un paso directo de una única entrada a una única salida.

Estas observaciones están respaldadas por los informes de tiempos y por los dibujos que muestra el Post-Fit Technology Map Viewer de Quartus. En concreto, esos inútiles bloques combinacionales se ven claramente en esas fuentes de información.

Es muy probable que todo este asunto varíe de una familia de FPGA a otra. En cuanto a Cyclone IV, solo tiene sentido usar primitivas DDR para las salidas.

Aún más importante: el hecho de que se use una salida de primitiva DDR cuando se necesita un registro de salida permite generar un reloj de salida alineado con las demás salidas. Para conseguirlo, alimenta una primitiva de salida DDR con un '1' constante en el puerto datain_h y un '0' constante en datain_l. En cuanto a las demás salidas, exige que se empaqueten registros de salida. Así, las transiciones de las demás salidas quedan alineadas con el flanco de subida del reloj que sale del bloque DDR.

Bueno, casi. El análisis de tiempos de un reloj de salida es distinto, porque el reloj conmuta un multiplexor que selecciona cuál de los dos registros de salida alimenta la salida (desplázate horizontalmente para ver los detalles):

+------------------------------------------------------------------------------------------------------------------------------------+
; Data Arrival Path                                                                                                                  ;
+---------+---------+----+------+--------+-------------------------+-----------------------------------------------------------------+
; Total   ; Incr    ; RF ; Type ; Fanout ; Location                ; Element                                                         ;
+---------+---------+----+------+--------+-------------------------+-----------------------------------------------------------------+
; 0.000   ; 0.000   ;    ;      ;        ;                         ; launch edge time                                                ;
; 0.000   ; 0.000   ;    ;      ;        ;                         ; clock path                                                      ;
;   0.000 ;   0.000 ; R  ;      ;        ;                         ; clock network delay                                             ;
; 0.000   ; 0.000   ; R  ;      ; 1      ; PIN_B12                 ; osc_clock                                                       ;
; 5.610   ; 5.610   ;    ;      ;        ;                         ; data path                                                       ;
;   0.000 ;   0.000 ; RR ; IC   ; 1      ; IOIBUF_X19_Y29_N8       ; osc_clock~input|i                                               ;
;   0.667 ;   0.667 ; RR ; CELL ; 2      ; IOIBUF_X19_Y29_N8       ; osc_clock~input|o                                               ;
;   0.853 ;   0.186 ; RR ; IC   ; 1      ; CLKCTRL_G12             ; osc_clock~inputclkctrl|inclk[0]                                 ;
;   0.853 ;   0.000 ; RR ; CELL ; 165    ; CLKCTRL_G12             ; osc_clock~inputclkctrl|outclk                                   ;
;   1.971 ;   1.118 ; RR ; IC   ; 1      ; DDIOOUTCELL_X16_Y29_N11 ; sram_controller_ins|ddr_clk|auto_generated|ddio_outa[0]|muxsel  ;
;   3.137 ;   1.166 ; RR ; CELL ; 1      ; DDIOOUTCELL_X16_Y29_N11 ; sram_controller_ins|ddr_clk|auto_generated|ddio_outa[0]|dataout ;
;   3.137 ;   0.000 ; RR ; IC   ; 1      ; IOOBUF_X16_Y29_N9       ; sram_clk~output|i                                               ;
;   5.610 ;   2.473 ; RR ; CELL ; 1      ; IOOBUF_X16_Y29_N9       ; sram_clk~output|o                                               ;
;   5.610 ;   0.000 ; RR ; CELL ; 0      ; PIN_E10                 ; sram_clk                                                        ;
+---------+---------+----+------+--------+-------------------------+-----------------------------------------------------------------;

Observa que esto no es un análisis de registro a pin, sino de reloj a pin. Una restricción set_output_delay incluirá este camino de todas formas. Sin embargo, una restricción set_max_delay de registros a puertos, si se usa, no incluirá este camino, así que hay que tratarlo aparte. En otras palabras, si se usa set_max_delay, debe tener esta forma:

set_max_delay -from [get_clocks main_clk] -to [get_ports sram_clk] 3.8

Ahora compara esto con otro pin con el mismo estándar de tensión, etc., pero excitado por un registro:

+----------------------------------------------------------------------------------------------------------------------+
; Data Arrival Path                                                                                                    ;
+---------+---------+----+------+--------+-------------------------+---------------------------------------------------+
; Total   ; Incr    ; RF ; Type ; Fanout ; Location                ; Element                                           ;
+---------+---------+----+------+--------+-------------------------+---------------------------------------------------+
; 0.000   ; 0.000   ;    ;      ;        ;                         ; launch edge time                                  ;
; 2.507   ; 2.507   ;    ;      ;        ;                         ; clock path                                        ;
;   0.000 ;   0.000 ;    ;      ;        ;                         ; source latency                                    ;
;   0.000 ;   0.000 ;    ;      ; 1      ; PIN_B12                 ; osc_clock                                         ;
;   0.000 ;   0.000 ; RR ; IC   ; 1      ; IOIBUF_X19_Y29_N8       ; osc_clock~input|i                                 ;
;   0.667 ;   0.667 ; RR ; CELL ; 2      ; IOIBUF_X19_Y29_N8       ; osc_clock~input|o                                 ;
;   0.853 ;   0.186 ; RR ; IC   ; 1      ; CLKCTRL_G12             ; osc_clock~inputclkctrl|inclk[0]                   ;
;   0.853 ;   0.000 ; RR ; CELL ; 165    ; CLKCTRL_G12             ; osc_clock~inputclkctrl|outclk                     ;
;   1.970 ;   1.117 ; RR ; IC   ; 1      ; DDIOOUTCELL_X37_Y29_N11 ; sram_controller_ins|dq_wr_data[6]|clk             ;
;   2.507 ;   0.537 ; RR ; CELL ; 1      ; DDIOOUTCELL_X37_Y29_N11 ; sram_controller:sram_controller_ins|dq_wr_data[6] ;
; 5.645   ; 3.138   ;    ;      ;        ;                         ; data path                                         ;
;   2.717 ;   0.210 ;    ; uTco ; 1      ; DDIOOUTCELL_X37_Y29_N11 ; sram_controller:sram_controller_ins|dq_wr_data[6] ;
;   3.182 ;   0.465 ; RR ; CELL ; 1      ; DDIOOUTCELL_X37_Y29_N11 ; sram_controller_ins|dq_wr_data[6]|q               ;
;   3.182 ;   0.000 ; RR ; IC   ; 1      ; IOOBUF_X37_Y29_N9       ; sram_dq[6]~output|i                               ;
;   5.645 ;   2.463 ; RR ; CELL ; 1      ; IOOBUF_X37_Y29_N9       ; sram_dq[6]~output|o                               ;
;   5.645 ;   0.000 ; RR ; CELL ; 1      ; PIN_G14                 ; sram_dq[6]                                        ;
+---------+---------+----+------+--------+-------------------------+---------------------------------------------------;

El tiempo total de reloj a salida (clock-to-output) no difiere en más de 35 ps, aunque el segundo camino, a simple vista, sea completamente distinto. Esto no es casualidad. La FPGA está claramente diseñada para que esta similitud se produzca. En concreto, el análisis de tiempos anterior es con el modelo lento (slow), 1200 mV y una temperatura de 100 °C, pero esta pequeña diferencia se mantiene también en las demás condiciones analizadas.

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)