2
\$\begingroup\$

For HDL design I'm currently developing for a zynq SoC, I need to invert a clock signal because of a swapped differential pair on board level.

Using "NOT" to invert adds a LUT in the path and as such introduces skew of at least 500ps between the inverted one and the original one (which is also put on an other differential output. And this is too much in our case.

Is there a way to invert a clock signal so that the skew between the original and the inverted copy is minimal?

I have found a possible solution using the ODDR primitive but this seems more like a workaround than a solution.

Thanks in advance.

\$\endgroup\$
  • \$\begingroup\$ Is constraining the skew and just having synthesis do its job inserting extra delay on the original signal a possibility? \$\endgroup\$ – DonFusili Jul 24 '18 at 12:53
  • \$\begingroup\$ Can you implement a zero-delay buffer using a PLL resource? \$\endgroup\$ – Spehro Pefhany Jul 24 '18 at 14:50
  • \$\begingroup\$ @DonFusili It might be a possibility, so far I have never tried something like that. I will investigate and get back to you. \$\endgroup\$ – Thomas Jul 25 '18 at 9:05
  • \$\begingroup\$ @SpehroPefhany Using a PLL resource is probably out of the question since it is already the output of a PLL. Although it is possible to invert it by setting the phase to 180. The phase is already controlled dynamically and should be kept that way. I will investigate and get back to you. \$\endgroup\$ – Thomas Jul 25 '18 at 9:05
  • \$\begingroup\$ @Thomas changing the phase 180 degrees and keeping it dynamically controlled are not mutually exclusive. \$\endgroup\$ – DonFusili Jul 25 '18 at 14:02
1
\$\begingroup\$

With Xilinx devices, using an ODDR is actually the recommended way to output a clock signal on a pin, especially if you have tight timing constraints. Do this for both clk and clk180, and both will have the same, repeatable timing. It is not a workaround at all.

See comment on the Xilinx forum here by a Xilinx Engineer:

ODDR keeps the duty cycle and provides the best possible path. No routing of clock on any interconnect, clock remains on the global clock resources where they belong.

It's also mentioned in the Xilinx 7-Series Select IO user guide, page 128, section "OLOGIC Resources" > "Clock Forwarding":

Output DDR can forward a copy of the clock to the output. This is useful for propagating a clock and DDR data with identical delays, and for multiple clock generation

You could play around with balancing LUT delays with other LUTs, ODELAY, and constraints, but this will not approach the simplicity or timing predictability of the ODDR method.

\$\endgroup\$
0
\$\begingroup\$

You could try to add the same delay to both outputs. The trick is to introduce logic which can not be optimized away but adds a LUT delay.

You are probably familiar with using EXOR gates to conditionally invert a signal.

I would add an EXOR function to both output ports. One EXOR's "control" signal is high the other is not. The control signal into each EXOR gate must be such that it could change. e.g. a register which you can write a one or zero to. You never will do that but the synthesis tools does not know so it has to keep the EXOR gate. It can't optimize it away.


Yesterday I tried to prevent logic from being optimised away using various Xilinx constraints but failed. In the end I used the certain-to-work-method I described above but I used an input pin to make that the non-inverting LUT is not optimised away:

//
// 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   

This is the result of the outputs after place & route: enter image description here

\$\endgroup\$
  • \$\begingroup\$ I was also thinking something like adding a LUT to the non-inverted signals path but could not figure out any way to introduce one. It might be tricky to keep the synth tool from optimizing it away. I will try and report back. Thanks! \$\endgroup\$ – Thomas Jul 25 '18 at 9:08
  • \$\begingroup\$ This will work, but seems like an obfuscated workaround when the Zynq SoC has ODelay primitives. \$\endgroup\$ – DonFusili Jul 25 '18 at 10:57
  • \$\begingroup\$ The attribute to use in your code above would be keep, not optimize. \$\endgroup\$ – scary_jeff Aug 1 '18 at 8:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.