A false path says that a path need not be timed. Written between two whole clocks, it removes every path from one to the other, including any that are related and real. It is the easiest way to make a violation disappear and the hardest to notice afterwards.
# paths from clk_a to clk_b: (name, truly asynchronous?, slack in ns)
paths = [("p1", True, 0.30), ("p2", True, 0.10), ("p3", False, 0.40), ("p4", False, -0.05), ("p5", False, 0.02), ("p6", False, 0.15)]
removed = [p for p in paths] # set_false_path -from clk_a -to clk_b removes all six
intended = [p for p in paths if p[1]]
hidden = [p for p in paths if not p[1]]
assert len(removed) == 6 and len(intended) == 2 and len(hidden) == 4
hidden_violations = [p[0] for p in hidden if p[2] < 0]
assert hidden_violations == ["p4"]
# a scoped exception (only the synchroniser input pins of the two asynchronous crossings) keeps the others
scoped_removed = [p[0] for p in paths if p[1]]
assert scoped_removed == ["p1", "p2"]
print("PASS: broad rule removed", len(removed), "paths, intended", len(intended), "; hidden real paths", len(hidden), "including violation", hidden_violations)# not-run: SDC is not executable here
# too broad: every path from clk_a to clk_b
set_false_path -from [get_clocks clk_a] -to [get_clocks clk_b]
# scoped: only the two known asynchronous crossings, ending at the synchroniser inputs
set_false_path -from [get_clocks clk_a] -to [get_pins u_sync1/D]
set_false_path -from [get_clocks clk_a] -to [get_pins u_sync2/D]The broad rule removes six paths; only two (p1, p2) are really asynchronous crossings. The other four are related paths that happen to cross between the clocks, and one of them (p4) has a -0.05 ns violation that is now invisible. The scoped version ends at the synchroniser input pins and removes exactly the two intended paths. Crossings of this kind are normally also bounded with a maximum delay rather than left as an unbounded false path. The audit that finds the problem is a count of paths covered by each exception: an exception that covers many more paths than the engineer expected is wrong or too broad.
Each exception has a reason, an owner and a count of the paths it covers; the count is compared with what was expected.
False paths end at (-to) the synchroniser input pins, not whole-clock -from and -to, unless the clocks are truly unrelated everywhere.
Exceptions are reviewed again after any change to the clocking: relations that were async may now be related.
p4 is a related path: if it really violates, silicon can fail. Simulation rarely covers the worst corner and timing combination.