Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutRoadmapCareersInternshipsFAQContactPrivacyTerms
Skip to lesson

Course contents

  • Logic Synthesis Glossary
  • Logic Synthesis Cheatsheet
  • Synthesis Foundations14
  • Logic Optimisation and Mapping20
  • Constraints and Timing15
    • SDC for Synthesis
      • Clocks and Generated Clocks
      • Uncertainty, Latency and IO Delays
      • Driving Cells, Loads and Units
      • False, Multicycle and Max-Delay Paths
      • Missing and Over-Tight Constraints
    • Delay Models and Slack
    • Timing-Driven Synthesis
  • Sequential, FSM and Memory19
  • Datapath Synthesis14
  • Area, Power and Test14
  • Verification, ECO and Handoff15
  • Flows and Debugging15
  • Interview and Judgment11
Loading lesson

←SDC for Synthesis
  1. Topics
  2. Logic Synthesis
  3. Constraints and Timing
  4. SDC for Synthesis
  5. Driving Cells, Loads and Units
On this page

    Part 3 of 9, lesson 3 of 15Part 3 of 9/Constraints and Timing/Lesson 3 of 15Intermediate

    Driving Cells, Loads and Units

    Drive and load bounds on ports, with EXAMPLE time and capacitance units.

    Drive and load decide the edges, and the units decide the meaning: one unconverted number can make a load a thousand times heavy without a single error message. One cone under two recorded loads shows both the rebuild and the trap.

    After this lesson you can: map set_driving_cell and set_load onto consumed constraint lines, convert library picofarads to tool femtofarads, and read a load-driven rebuild out of area, delay, and histograms.

    The question

    Delays bound how much time the outside world takes; drive and load bound how fast the edges move. An input port needs a model of what drives it, because a weak driver stretches the incoming transition and a strong one sharpens it. An output port needs the capacitance it must charge, because a heavier load slows every transition the tool computes. Without those two bounds the tool still maps the logic, but it times the edges against an assumption nobody stated.

    This lesson runs one cone twice under two recorded loads and reads the difference back from the tool reports. The SDC that states the bounds is illustrative, as always here, but the constraint lines the run actually consumed are recorded, and the table below keeps those two columns apart.

    The two lines and what they map to

    The SDC pair names a library cell to drive the input and a capacitance for the output. The driving-cell line says the tool should treat input a as driven by a BUF from the teaching library, which fixes the input transition it assumes. The load line says output y carries a capacitance in library units, which fixes how hard the final stage works. Units are part of both lines, and the next section shows why the load unit is the one that bites.

    Diagram
    # not-run: no SDC reader in the open tools
    set_driving_cell -lib_cell BUF [get_ports a]
    set_load 0.05 [get_ports y]

    The open flow cannot read that SDC, so the script hands ABC the same two facts through its constraint files: typical.constr for the light run, heavy.constr for the heavy one. Both files name the same BUF driver; they differ only in the load number. The ABC log echoes each file back as it reads it, and those echo lines are recorded, so the mapping from SDC idea to consumed constraint is proven rather than asserted.

    SDC idea (illustrative)

    Constraint line the run consumed (recorded)

    set_driving_cell -lib_cell BUF on the input

    ABC: Setting driving cell to be "BUF".

    set_load 0.05 on the output, in library capacitance units

    ABC: Setting output load to be 50.000000.

    One cone, two loads

    The design is a six-input OR of ANDs feeding one output: three AND pairs ORed together, small enough to draw and load-sensitive at its final stage. The script synthesises it once, saves the generic gates, then maps the same gates twice against sized.lib at the same 300 ps delay target: once with the light load, once with the heavy one. Both runs write their ABC report, their stat histogram, and their netlist. The assertions prove no generic gate survives either mapping, that the light run uses no upsized cell, and that the heavy run contains at least one BUF_X4.

    yosys
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    read_verilog <<EOV
    module cone6(input a, b, c, d, e, f, output y);
    assign y = (a & b) | (c & d) | (e & f);
    endmodule
    EOV
    synth -top cone6 -flatten
    design -save generic
    tee -o abc_typical.txt abc -liberty sized.lib -constr typical.constr -D 300
    tee -o stat_typical.txt stat -liberty sized.lib
    write_json net_typical.json
    select -assert-none t:$and t:$or t:$xor t:$xnor t:$mux t:$not
    select -assert-none t:$_AND_ t:$_OR_ t:$_XOR_ t:$_XNOR_ t:$_MUX_ t:$_NOT_ t:$_NAND_ t:$_NOR_
    select -assert-none t:*_X2 t:*_X4
    design -load generic
    tee -o abc_heavy.txt abc -liberty sized.lib -constr heavy.constr -D 300
    tee -o stat_heavy.txt stat -liberty sized.lib
    write_json net_heavy.json
    select -assert-none t:$and t:$or t:$xor t:$xnor t:$mux t:$not
    select -assert-none t:$_AND_ t:$_OR_ t:$_XOR_ t:$_XNOR_ t:$_MUX_ t:$_NOT_ t:$_NAND_ t:$_NOR_
    select -assert-min 1 t:BUF_X4
    log PASS: the same target maps one cone two ways under two loads

    The delay target stays fixed, so the load is the only variable: whatever differs in the reports below is the price of that number.

    What the runs recorded

    Predict first The load quadruples from 50 to 200 fF at a fixed 300 ps target. Will ABC return the same netlist with a slower arrival, or a different netlist?

    A different netlist. The light run maps to 4 cells with area 9; the heavy run needs 5 cells with area 14.2, including its asserted BUF_X4 driving the load. The load does not just slow the report; it rebuilds the output stage.

    Load (recorded)

    Cells (recorded)

    Area (recorded)

    Delay reached (recorded)

    Upsized cells (recorded)

    Inserted buffers (recorded)

    50 fF

    4

    9

    208 ps

    0

    0

    200 fF

    5

    14.2

    290 ps

    0

    1

    Read the table as cause and effect. The light run reports 4 cells (NAND2 x3, NAND3 x1) at area 9 and 208 ps, comfortably inside the 300 ps target with no upsized cell and no inserted buffer. The heavy run reports 5 cells (BUF_X4 x1, NAND2 x3, NAND3 x1) at area 14.2 and 290 ps: the same logic plus one large buffer on the output, still inside the target because the buffer was bought to stay there. That buffer is the load made visible, and the split columns keep it apart from upsizing: an inserted buffer is a new cell, not a bigger one.

    Recorded light-load netlist: the cone mapped with no upsized cell.
    Recorded heavy-load netlist: the same cone with one inserted output buffer, highlighted.
    Recorded area under the two loads: the heavy bar carries the extra buffer.

    The unit trap

    The teaching library prices capacitance in picofarads, so the SDC load means 0.05 pF. ABC reads its constraint number as femtofarads, and 0.05 pF is 50 fF, which is exactly what typical.constr carries. Two different units, one correct handoff, and the run proves it: the log line in the table above reads the 50 back. State the unit on every side of the handoff, because nothing in the number itself says which unit it is.

    The trap runs in both directions, one per slot. A bare 50 typed into the SDC slot, which reads library picofarads, means 50 pF: 50000 fF, a thousand times the intended load, so the tool buffers an output that needs no buffering. The library number typed unchanged into the ABC slot, which reads femtofarads, means 0.05 fF: a thousand times too light, so the tool trusts edges the real load will collapse. A bare 50 where femtofarads are read is simply 50 fF, the correct value. The program below pins the correct conversion and both thousand-fold mistakes.

    example.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    import sys
    
    # Unit handoff for set_load. The SDC slot reads library picofarads; the ABC
    # slot reads femtofarads. Every check converts through the slot's own unit,
    # so a conversion in the wrong direction fails instead of cancelling out.
    FF_PER_PF = 1000
    INTENDED_PF = 0.05
    intended_ff = INTENDED_PF * FF_PER_PF
    
    if intended_ff != 50.0:
        print("FAIL: 0.05 pF converts to " + str(intended_ff) + " fF, want 50.0")
        sys.exit(1)
    
    # Trap A: a bare 50 typed into the SDC slot, which reads picofarads.
    SDC_ENTRY_A = 50.0
    trap_a_ff = SDC_ENTRY_A * FF_PER_PF
    if trap_a_ff != 50000.0:
        print("FAIL: 50 pF converts to " + str(trap_a_ff) + " fF, want 50000.0")
        sys.exit(1)
    if trap_a_ff / intended_ff != 1000.0:
        print("FAIL: SDC-side mistype is not 1000x heavy")
        sys.exit(1)
    
    # Trap B: the library number typed into the ABC slot, which reads femtofarads.
    ABC_ENTRY_B = 0.05
    trap_b_pf = ABC_ENTRY_B / FF_PER_PF
    if trap_b_pf != 0.00005:
        print("FAIL: 0.05 fF is " + str(trap_b_pf) + " pF, want 0.00005")
        sys.exit(1)
    if intended_ff / ABC_ENTRY_B != 1000.0:
        print("FAIL: ABC-side mistype is not 1000x light")
        sys.exit(1)
    
    print("PASS: 0.05 pF is 50 fF and each one-sided mistype misses 1000x")

    Read the program as the rule. Convert at the boundary, every time, and check the log echo the way the table above does. A load without a unit is an unread number, and the thousand-fold gap is what unread numbers cost.

    Break it: quadruple the load

    The heavy run in the script is the break-it: the same cone, the same target, the same BUF driver, with the load quadrupled. Nothing else changed, so the whole difference is the load. The area moves from its light row to its heavy row, the delay follows, and the netlist gains exactly one cell: the BUF_X4 the assertion demands. In this run the load left the logic cover alone and paid only at the output stage; two load points cannot prove that always happens, so read it as what this cone did, not as a law of loads.

    An unbound port leaves the tool timing edges against an unstated assumption, and a wrong-unit bound replaces it with a wrong stated one. Both fail silently. Read the constraint echo in the log after every edit.

    What does each bound change, and why do units matter?

    • Weak answer: drive and load only change the report numbers, and units are cosmetic because the tool normalises them.

    • Strong answer: the driving cell fixes the input transition and the load fixes the output effort; here quadrupling the load at a fixed target rebuilds the output stage, moving delay from 208 ps to 290 ps and inserting the asserted output buffer. Units matter because the SDC slot reads picofarads while the ABC slot reads femtofarads: 0.05 in SDC means 0.05 pF arriving as 50, a bare 50 in SDC would mean 50 pF and read a thousand times heavy, and 0.05 typed into the ABC slot would mean 0.05 fF and read a thousand times light.

    • Follow-up: the delay report jumps after a constraint edit but the RTL never changed. What do you read first? The constraint echo in the log, then the units on each side of the handoff.

    Check yourself The light and heavy constraint files name the same driver with different load numbers. What are the two numbers, and which run contains the large output buffer?

    50 and 200, read as femtofarads. The heavy run contains the asserted BUF_X4, because its output works four times as hard at the same delay target.

    Check yourself The library load 0.05 is typed unchanged into each slot. What does each slot read, and what follows?

    The intent is 0.05 pF, which is 50 fF. Typed into the SDC slot, 50 means 50 pF, a thousand times heavy: needless buffering and fiction delays. Typed into the ABC slot, 0.05 means 0.05 fF, a thousand times light: edges the real load will collapse. Only 50 in the femtofarad slot is correct, as the program proves.

    • The driving cell fixes the input transition; the load fixes the output effort, up to inserting a buffer.

    • The library prices picofarads while ABC reads femtofarads: convert at the boundary and check the log echo.

    • A heavier load rebuilds the output stage; it does not just slow the report.

    Rule of thumb: convert units at the boundary and read the constraint echo in the log after every edit.

    How this was checked

    Cell counts, areas, delays, histograms, netlist pictures, and constraint echo lines on this page come from one Yosys 0.70 run of the script shown, recorded by the course checker (scripts/tools/run-rtl-testbenches.mjs with COURSE=synth): ABC maps one cone against the teaching library sized.lib at a fixed 300 ps target with typical.constr (BUF driver, 50 fF load) and heavy.constr (BUF driver, 200 fF load). The library is fictional, so absolute areas and delays are teaching units; the rebuild and the unit handoff are the point. The SDC listing is illustrative: the open tools have no SDC reader.

    • Interview: run a mock interview on this topic

    Related topics

    • False, Multicycle and Max-Delay Paths

    • Timing-Driven Synthesis

    • See also: RTL for Timing

    Previous

    39 / 139

    Next: False, Multicycle and Max-Delay Paths

    Up next

    Up nextFalse, Multicycle and Max-Delay Paths

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • Clocks and Generated Clocks
    • Missing and Over-Tight Constraints