# FPGA automatic pipelining?

I have a synchronous datapath in my design that fails negative slack timing check, and I could most likely fix it by putting extra pipeline registers between datapath blocks by changing RTL sources.

I've also tried constraining multicycle path like this (made a simple test project to figure out how timing constraints work, they're new to me):

# tell the router that 'do' should be 5 cycles late
set_multicycle_path -setup 5 -to [get_ports {do}]


I, for some reason, expected the router to put extra registers on the path to 'do' output port to increase latency, but it tried to make a very long net and still failed timing. I do suspect now, that since pipelining involves changing RTL behavior, router and its timing checks have nothing to do with that, and those constraints are only for setting timing requirements.

I then tried to do this:

# don't care how fast the route is as long as it's up
# to 5 cycles
set_multicycle_path -setup 5 -to [get_ports {do}]
set_multicycle_path -hold 4 -to [get_ports {do}]


This fixed timing checks, but still no extra pipelining and now I can't be sure how quick the path is unless I specifically look at timing. I think this would become a problem when constraining a bus that way since the different lines in it might pass timing check, but still might be out of alignment with each other.

So here's the question: is there any way to make the FPGA tools do the work of figuring out how much pipelining a path needs and then inserting it automatically?

• Is your negative slack violation associated with external input signals? Did you synchronize your inputs? – Al Bundy Nov 26 '17 at 7:53
• Negative slack in my actual design happens inside the datapath. The datapath is being fed with data from external LVDS DDR ADC through a typical input stage consisting of IBUFDS, IDELAYE2, IDDR and IN_FIFO primitives (this is a Xilinx device). Both FPGA and ADC are clocked from the same clock source. – Alexei Nov 26 '17 at 15:12

First and foremost, timing constraints are not used to add logic. The purpose of these constraints is to tell the static timing analysis (STA) tools what your logic does. The emphasis is on your logic. It is your job as the designer of the circuit to add any pipelining that may be needed into the HDL yourself.

Secondly, the set_multicycle_path is not designed to explain pipeline registers. The purpose of it is to say to the STA tools about a register which has a clock enable with a known period.

Lets use an example. If you have a data path between two registers which are both only clocked once every 5 cycles, you can set a multi-cycle path constraint between the two registers so that the STA tools know that the propagation delays for that path can be 5 clock cycles without causing setup violations. This doesn't add logic, so unless you implement what you have constrained the constraint will be invalid and will hide potential timing violations.

Pipelining is nothing like a multi-cycle path. Even though to get data from one "input" register to an "output" register you might have multiple registers in a chain, the path between each register is still only once clock cycle, so not a multi-cycle path. The reason pipelining works is that you take a long combinational path and rather than waiting multiple cycles before you clock the output, instead you add registers to break the calculation up into shorter steps.

The synthesis tools cannot add this pipelining for you for the simple reason that adding pipeline registers changes the design latency. Could you imagine trying to compare two numbers in a design, one from a short combinational path, the other from a long one, only to find that the tools added 5 cycles of pipeline to the long path. Your whole design would get out of sync.

• You make a really good point in the last paragraph, it somehow hasn't occured to me :P It seems that there's a lot of information on using multicycle paths out there, but I couldn't really find a lot of explanations about the use-cases, although after your reply, it now seems really obvious. – Alexei Nov 26 '17 at 15:49

I am not aware of any tool having that option. The closest is the 'register balancing' support in e.g. Synopsys synthesis. There YOU put X register stages at the output and the tool pushes them into the design to get timing closure. I don't know in how far this is supported by synthesis tools from other vendors. What you are doing is absolutely incorrect!!! You can't just set a multi cycle path and "find" that your problem has gone away. The timing error is still there, your circuit will still fail but the tool will be silent about it. So instead of an error you now have an error which is ignored by the tool.

This fixed timing checks

Not it does not! What you are doing is absolutely incorrect!!! You can't just set a multi cycle path and "find" that your problem has gone away. The timing error is still there, your circuit will still fail but the tool will be silent about it. So instead of an error you now have an error which is ignored by the tool.
There are numerous pitfall with multi cycle paths. This may sound pedantic but: From what I read I think you should not touch multi-cycle path settings until you have some more experience and know what you are doing.
The closest to 'automatic' solving your probem is:

• Check if your tool has register balancing.
• If so take your negative slack and divide it by the clock period.
• Round the number up to the nearest integer.
• Add that number of register stages at the output.
• Synthesis with register balancing on.

Otherwise you are back to having to figure out yourself the best place to put a register stage in.

• @Alexei, if you are using Xilinx or Intel (formerly Altera) FPGAs, their tools support register balancing/retiming. Here is a similar question, however my answer was mostly for Design Compiler. – ahmedus May 1 '18 at 22:51