Skip to main content

vehicle_macro_sdc

Function vehicle_macro_sdc 

Source
pub fn vehicle_macro_sdc(
    pdk: &PdkTarget,
    clock: HarnessClock,
) -> Result<String, PdkUnsupported>
Expand description

The constraints a vehicle user macro is timed with: OpenLane’s own base.sdc, then the vehicle’s timing as it characterizes it (HarnessTiming) — the clock model the chip is signed off with, and every synchronous harness input’s minimum delay.

The inputs: base.sdc gives every input one delay, IO_PCT of the period, as both its earliest and latest arrival — 8 ns at 40 ns — so a port-to-flop path looks hold-safe inside the macro and is violated one level up, where the harness delivers the Wishbone bus under 2 ns after the edge. With the real minimum on the ports, the macro’s own hold repair closes exactly those paths, and nothing else needs a margin. MEASURED on wpe_user_project (RUN_2026.09.25_22.53.44): the global 0.7 ns hold margin that closed dram_user_project’s 97 port-to-flop paths found 35,656 hold endpoints in the engine’s 32,773 flops and inserted 81,316 buffers, 0.81 mm²; the macro went from 32% to 41% utilization and global routing failed on congestion (GRT-0119).

The clock: base.sdc’s 0.25 ns uncertainty and 5 % derate are OpenLane’s defaults, not the chip’s; Caravel signs itself off at 0.1 ns and 3.75 %, and those are set after base.sdc so they are the ones in force. MEASURED on the engine’s post-CTS placement (RUN_2026.09.26_03.38.30, all three corners, OpenLane’s 0.1 ns repair margin): under the defaults 31,793 of its 35,747 flops fell inside the margin and took a buffer each (32,005), leaving global routing 55 gcells short; 31,089 of them were flops holding their own value through an enable mux — launch and capture on the same flop and the same edge, a path skew cannot reach — and only 87 had negative slack. Under the chip’s model 6 endpoints fall inside the margin and 1 is negative: the wbs_cyc_i port path, a real violation the repair closes either way.

clock is the harness clock the macro’s logic runs on, its CLOCK_PORT. On HarnessClock::User2 the harness’s bus keeps its own clock: wb_clk_i becomes a clock at the chip’s core period, asynchronous to the macro’s, and every port the harness times against it (HarnessTiming::core_clock_inputs and core_clock_outputs) moves from base.sdc’s delay against CLOCK_PORT to one against wb_clk_i. Each removal names the clock it removes: MEASURED in the pinned OpenSTA, unset_input_delay without -clock removes only the delays that have no clock, and write_sdc still showed wb_clk_i delayed against user_clock2.