The longest topological path counts gates from an input to an output. It ignores cell delays and wire load, so it measures structure rather than time.
The three-gate example has depth 2: one AND level feeding one OR level. The calc block works it out pin by pin.
gate list: AND2(a, b -> n1), AND2(c, d -> n2), OR2(n1, n2 -> y)
depth of inputs a, b, c, d = 0
depth of n1 = 1 + max(0, 0) = 1
depth of n2 = 1 + max(0, 0) = 1
depth of y = 1 + max(1, 1) = 2 logic levels
longest topological path: a -> n1 -> y (2 gates)ltp prints that path for the whole design. The block below is an illustrative layout, numbers invented for this lesson.
illustrative layout, numbers invented for this lesson (an example chain, never tool output):
path: in -> g1 -> g2 -> g3 -> out
gates on path = 3, nets on path = 4
depth = 3 logic levels (topological; delays ignored)write_verilog prints the netlist to a file. Reading it back must restore the same cells, or the file is corrupt.
The script below writes the three-gate netlist, resets the design, reads the file back and pins the same counts. Its ltp call prints the path first.
read_verilog <<EOV
module top(input a, b, c, d, output y);
wire n1, n2;
assign n1 = a & b;
assign n2 = c & d;
assign y = n1 | n2;
endmodule
EOV
hierarchy -check -top top
select -assert-count 2 t:$and
select -assert-count 1 t:$or
stat
ltp
write_verilog netlist.v
design -reset
read_verilog netlist.v
hierarchy -check -top top
select -assert-count 2 t:$and
select -assert-count 1 t:$or
stat
log PASS: written netlist reads back with identical countsThe hand recount below replays the same gate list on paper. Its numbers match the asserted blocks: 3 cells, 7 wires, depth 2 and maximum fanout 1.
printed gate list: AND2(a, b -> n1), AND2(c, d -> n2), OR2(n1, n2 -> y)
cells by type: AND2 2, OR2 1
total cells = 2 + 1 = 3
wires: a, b, c, d, n1, n2, y = 7
depth of y = 2 logic levels (from the first section)
every driven internal net has fanout 1 (the output port y has no internal loads), so the maximum fanout is 1The program below recounts the list independently. It passes only when cells, wires, depth and fanout all agree.
import sys
gates = [
("AND2", ("a", "b"), "n1"),
("AND2", ("c", "d"), "n2"),
("OR2", ("n1", "n2"), "y"),
]
roots = ("a", "b", "c", "d")
depth = {}
for r in roots:
depth[r] = 0
fanout = {}
for g in gates:
kind, ins, out = g
depth[out] = 1 + max(depth[i] for i in ins)
for i in ins:
fanout[i] = fanout.get(i, 0) + 1
wires = set(roots)
for g in gates:
kind, ins, out = g
wires.add(out)
counts = {}
for g in gates:
counts[g[0]] = counts.get(g[0], 0) + 1
bad = 0
if len(gates) != 3:
print("FAIL: cell total is " + str(len(gates)) + " want 3")
bad = 1
if counts.get("AND2", 0) != 2:
print("FAIL: AND2 count is " + str(counts.get("AND2", 0)) + " want 2")
bad = 1
if counts.get("OR2", 0) != 1:
print("FAIL: OR2 count is " + str(counts.get("OR2", 0)) + " want 1")
bad = 1
if len(wires) != 7:
print("FAIL: wire total is " + str(len(wires)) + " want 7")
bad = 1
if depth["y"] != 2:
print("FAIL: depth of y is " + str(depth["y"]) + " want 2")
bad = 1
if max(fanout.values()) != 1:
print("FAIL: maximum fanout is " + str(max(fanout.values())) + " want 1")
bad = 1
if bad != 0:
sys.exit(1)
print("PASS: recount gives 3 cells, 7 wires, depth 2, max fanout 1")It counts gates on the longest path. It ignores cell delays and wire load.
It proves the round trip preserved the structure. It leaves open whether the netlist still matches the RTL, which needs an equivalence check.