Reloj invertido Xilinx ZYNQ/ARTIX7 sin inducir sesgo

Para el diseño HDL que estoy desarrollando actualmente para un SoC zynq, necesito invertir una señal de reloj debido a un par diferencial intercambiado a nivel de placa.

El uso de "NOT" para invertir agrega una LUT en la ruta y, como tal, introduce un sesgo de al menos 500ps entre el invertido y el original (que también se coloca en otra salida diferencial. Y esto es demasiado en nuestro caso).

¿Hay alguna manera de invertir una señal de reloj para que el sesgo entre el original y la copia invertida sea mínimo?

Encontré una posible solución utilizando la primitiva ODDR, pero esto parece más una solución temporal que una solución.

Gracias de antemano.

¿Es posible restringir el sesgo y simplemente hacer que la síntesis haga su trabajo insertando un retraso adicional en la señal original?
¿Puede implementar un búfer de cero demoras utilizando un recurso PLL?
@DonFusili Podría ser una posibilidad, hasta ahora nunca he probado algo así. Voy a investigar y me pondré en contacto contigo.
@SpehroPefhany El uso de un recurso PLL probablemente esté fuera de discusión, ya que ya es el resultado de un PLL. Aunque es posible invertirlo configurando la fase a 180. La fase ya está controlada dinámicamente y debe mantenerse así. Voy a investigar y me pondré en contacto contigo.
@Thomas cambiar la fase 180 grados y mantenerla controlada dinámicamente no se excluyen mutuamente.
Supongo que ya encontró una solución, pero solo quería comentar: ¿la negación de una señal (a través de la lógica basada en LUT) no introduce necesariamente la posibilidad de fallas en las transiciones? Varias otras respuestas/comentarios parecen sugerir que funcionará (y solo señalan que es una solución inconveniente/intrincada); me parece que no puede funcionar. ¿Me estoy perdiendo de algo?

Respuestas (2)

Con los dispositivos Xilinx, usar un ODDR es en realidad la forma recomendada de generar una señal de reloj en un pin, especialmente si tiene restricciones de tiempo estrictas. Haga esto para ambos clky clk180, y ambos tendrán el mismo tiempo repetible. No es una solución en absoluto.

Vea el comentario en el foro de Xilinx aquí por un ingeniero de Xilinx:

ODDR mantiene el ciclo de trabajo y proporciona la mejor ruta posible. Sin enrutamiento de reloj en ninguna interconexión, el reloj permanece en los recursos de reloj global a los que pertenecen.

También se menciona en la guía del usuario de Xilinx 7-Series Select IO , página 128, sección "Recursos OLÓGICOS" > "Reenvío de reloj":

Salida DDR puede reenviar una copia del reloj a la salida. Esto es útil para propagar un reloj y datos DDR con retrasos idénticos y para la generación de múltiples relojes.

Puede jugar con el equilibrio de los retrasos de LUT con otros LUT, ODELAY y restricciones, pero esto no se acercará a la simplicidad o la previsibilidad de tiempo del método ODDR.

Podría intentar agregar el mismo retraso a ambas salidas. El truco es introducir una lógica que no se pueda optimizar pero que agregue un retraso de LUT.

Probablemente esté familiarizado con el uso de puertas EXOR para invertir condicionalmente una señal.

Agregaría una función EXOR a ambos puertos de salida. La señal de "control" de un EXOR es alta y la otra no. La señal de control en cada puerta EXOR debe ser tal que pueda cambiar. por ejemplo, un registro en el que puede escribir un uno o un cero. Nunca harás eso, pero las herramientas de síntesis no lo saben, por lo que debe mantener la puerta EXOR. No puede optimizarlo.


Ayer traté de evitar que la lógica se optimizara utilizando varias restricciones de Xilinx, pero fallé. Al final, utilicé el método de trabajo seguro que describí anteriormente, pero usé un pin de entrada para hacer que la LUT no inversora no esté optimizada:

//
// Same delay path for o1 and o2 
// where o2 = ~o1
//
module keep (
   input  clk,
   input  reset_n,
   input  never_changes, // Always low 
   output o1,o2
  );

reg [1:0] count;

   // Some (arbitrary) test registers
   always @(posedge clk or negedge reset_n)
   begin
      if (!reset_n)
        count <= 2'b0;
      else
        count <= count + 2'b01;
   end  

/* 
   This did not work:   
   XOR2 X1(.I0(count[1]),.I1(1'b0),.O(o1));
   // synthesis attribute optimize of X1 is off
   XOR2 X2(.I0(count[1]),.I1(1'b1),.O(o2));
   // synthesis attribute optimize of X2 is off
 */
 // This can't fail: Note that never_changes should be low
   assign o1 = never_changes ^ count[1];
   assign o2 = ~count[1];

endmodule   

Este es el resultado de las salidas después de lugar y ruta:ingrese la descripción de la imagen aquí

También estaba pensando en algo como agregar un LUT a la ruta de señales no invertidas, pero no pude encontrar ninguna forma de introducir uno. Puede ser complicado evitar que la herramienta de sintetizador lo optimice. Voy a tratar de informar de nuevo. ¡Gracias!
Esto funcionará, pero parece una solución ofuscada cuando el Zynq SoC tiene primitivas ODelay.
El atributo a usar en su código anterior sería keep, not optimize.