The most expensive sentence in clock planning is these clocks are related, so we can treat them as synchronous. On NanoSoC it is half true: clk_cpu and clk_sys leave one VCO through two dividers, so their edges coincide by construction. But they travel through separate clock trees with independent insertion delay, and no balance constraint ties the two roots together. Signoff must assume the skew it cannot bound, which means asynchronous. This lesson draws that line precisely, because the FIFO-based CPU crossings exist only on the far side of it. Its one job is the signoff decision; the table that records it is next.
Phase-related describes silicon: at the divider outputs, every clk_sys rising edge coincides with a clk_cpu rising edge, every 10.417 ns. Synchronous for signoff demands more: a known, bounded phase between the clocks at every flop, proven by the trees. NanoSoC does not build that proof. The dividers feed separate roots, the trees balance each domain against itself, and process, voltage and temperature move the two delays independently. A 5.208 ns CPU period leaves no room for an unbounded inter-tree skew, so the methodology declares the pair asynchronous and every crossing between them gets a FIFO or a handshake. The crystal clock is the PLL's reference, so the three frequencies are locked in the exact ratio 8 : 4 : 1 and do not drift apart. What is unknown is the fixed phase offset at the flops: the PLL feedback is taken before the separate clock trees, and jitter adds to it. That offset is neither known nor bounded, so clk_per shares only the frequency ratio with the divided clocks and signs off as asynchronous to both.
# not-run: why the skew cannot be absorbed, NanoSoC teaching values
clk_cpu period 5.208 ns; clk_sys period 10.417 ns
Inter-tree skew is unbounded by construction (separate roots, separate trees).
A synchronous crossing would need skew + jitter + margin < period for every
flop pair, which no constraint states and no tree guarantees.
Therefore: the pair is declared asynchronous (one clock-group declaration),
the crossings X1/X2 use FIFOs, and the only extra constraints on them are the
bounded-delay and skew limits on pointers and handshake data.The clock-relationship document states per pair whether signoff is synchronous or asynchronous, with the tree evidence for each synchronous claim.
The pair is declared asynchronous in the constraints (one clock-group declaration). The only extra constraints on those paths are the bounded-delay and skew constraints on the FIFO pointers and handshake data; no other false path or multicycle crosses the pair, and the exception audit proves it.
The divider coincidence is still used where it is valid: testbench alignment and ratio sweeps, never latency bounds or timing closure.
Run the CDC signoff with the pair declared asynchronous and confirm every crossing is covered by a synchroniser or FIFO rule; a clean report on a synchronous declaration followed by failures on the asynchronous one means the design relied on the skew it never bounded. On silicon, failures that move with voltage and temperature while passing at nominal point at exactly this optimism.
A balanced tree from one root with a stated skew bound, timing constraints written against that bound, and margins that hold across corners. The cost is tree effort and lost flexibility; NanoSoC spends FIFOs instead.