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
    • Boolean Optimisation
    • Technology Mapping
    • Cell Libraries and Liberty
    • Structuring and Buffering
      • Fanout, Slew and Capacitance Rules
      • Delay of a Driver with Load
      • Buffer Trees
      • Sizing, Cloning and Restructuring
      • Fanout Constraints in Practice
  • Constraints and Timing15
  • Sequential, FSM and Memory19
  • Datapath Synthesis14
  • Area, Power and Test14
  • Verification, ECO and Handoff15
  • Flows and Debugging15
  • Interview and Judgment11
Loading lesson

←Structuring and Buffering
  1. Topics
  2. Logic Synthesis
  3. Logic Optimisation and Mapping
  4. Structuring and Buffering
  5. Delay of a Driver with Load
On this page

    Part 2 of 9, lesson 17 of 20Part 2 of 9/Logic Optimisation and Mapping/Lesson 17 of 20Intermediate

    Delay of a Driver with Load

    Driver delay against load, fitted to the real NAND2 table and checked.

    Guessing delay against load is how teams over-margin by nanoseconds or miss by picoseconds. One fitted line through the library row replaces both errors.

    After this lesson you can: fit delay against load from a copied library row, quote it with its slew, separate interpolation from extrapolation, and split a recorded arrival into the load's share and the repair's share.

    The question

    How much slower does a driver get as its load grows? The library answers with a table over input slew and output load, recoverable with a straight line between two points. This lesson fits that line through the real NAND2 row copied exactly from the library file, checks the fit in Python, then measures the heavier output load on a real mapped gate: the line prices the load's share, and the repair prices the rest.

    The real NAND2 row

    The sized library describes each timing arc as a small table over input slew and output load. For the NAND2 rise arc at 0.01 ns input slew, the row reads 0.08 ns at 0.01 pF and 0.10 ns at 0.1 pF, copied exactly from the file; the same arc at the slower 0.1 ns slew reads 0.11 and 0.14 ns. Everything here is built from those four digits plus the constraint loads, 0.05 and 0.2 pF.

    Input slew (ns)

    Load 0.01 pF

    Load 0.1 pF

    0.01

    0.08 ns

    0.10 ns

    0.10

    0.11 ns

    0.14 ns

    Fix the slew at 0.01 ns and read delay against load only. Two points make a line: the slope is the delay difference divided by the load difference, 0.02 ns over 0.09 pF, worked out in the arithmetic below. The model is the base delay plus the slope times the extra load past the first table point. It is exact at both table points by construction, and it is a fit, not the library: between the points the real cell interpolates exactly the same way at a fixed slew, past 0.1 pF the table ends and the line extrapolates, which the break-it section prices honestly.

    Diagram
    hand arithmetic from the copied fast-slew row:
    slope k = (0.10 - 0.08) / (0.1 - 0.01) = 0.02 / 0.09 = 0.2222 ns per pF
    model: D(C) = 0.08 + k x (C - 0.01), ns and pF
    typical output load: D(0.05) = 0.08 + k x 0.04 = 0.0889 ns (about 89 ps)
    heavy output load:   D(0.2)  = 0.08 + k x 0.19 = 0.1222 ns (about 122 ps, extrapolated)

    One gate, two output loads

    The script below maps a single NAND2 twice at a loose target, changing only the constraint file: typical at 0.05 pF, then heavy at 0.2 pF. Both runs keep every logic cell at size 1, as asserted, but the mapper may add its own answer on top, and under the heavy load it does. The program after the script checks the linear model against the copied row digits.

    yosys
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    read_verilog <<EOV
    module one(input a, input b, output y);
      assign y = ~(a & b);
    endmodule
    EOV
    synth -top one -flatten
    design -save generic
    tee -o abc_typ.txt abc -liberty sized.lib -constr typical.constr -D 1000
    tee -o stat_typ.txt stat -liberty sized.lib
    select -assert-count 1 t:NAND2 t:NAND2_X2 t:NAND2_X4
    select -assert-none t:*_X2 t:*_X4
    design -load generic
    tee -o abc_heavy.txt abc -liberty sized.lib -constr heavy.constr -D 1000
    tee -o stat_heavy.txt stat -liberty sized.lib
    select -assert-count 1 t:NAND2 t:NAND2_X2 t:NAND2_X4
    select -assert-none t:*_X2 t:*_X4
    log PASS: the same gate reports a longer delay under the heavier output load
    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
    import sys
    
    # Copied exactly from the NAND2 cell_rise row at 0.01 ns input slew in sized.lib:
    # index_2 loads 0.01 and 0.1 pF give delays 0.08 and 0.10 ns.
    C0, D0 = 0.01, 0.08
    C1, D1 = 0.1, 0.10
    K = (D1 - D0) / (C1 - C0)
    
    def model(c):
        return D0 + K * (c - C0)
    
    # Every check below names a literal with four decimals, so any drift in the
    # copied digits or the arithmetic fails loudly instead of comparing true.
    checks = [
        (round(K, 4), 0.2222),
        (round(model(0.01), 4), 0.08),
        (round(model(0.05), 4), 0.0889),
        (round(model(0.1), 4), 0.1),
        (round(model(0.2), 4), 0.1222),
    ]
    
    for i in range(len(checks)):
        got, want = checks[i]
        if got != want:
            print("FAIL: check " + str(i + 1) + " got " + str(got) + " want " + str(want))
            sys.exit(1)
    
    print("PASS: fast-slew slope reproduces the copied NAND2 row")

    The Python checks replay the copied table digits to four decimals. They prove the code agrees with the row, not that the row matches real silicon: the library is a teaching stand-in.

    What the two runs printed

    Predict first The heavy run drives four times the output load. Will its reported arrival be roughly four times slower?

    No, on both counts. Delay is a base plus slope times load, so quadrupling the load adds only the slope term, about 33 ps for the extra 0.15 pF. And the heavy run is not even the same netlist: it carries an inserted buffer the typical run does not need.

    Run

    Cells

    Area

    Arrival reported

    typical load (0.05 pF)

    1

    2

    94 ps

    heavy load (0.2 pF)

    2

    4

    234 ps

    Read the table against the model, and read the heavy netlist first. ABC's load-driven buffer step (the buffer command in the abc -D script) put a size-1 BUF in front of the 0.2 pF output, so the NAND2 now drives only the buffer's input pin and its own stage delay falls instead of rising. The 33 ps the model prices for the extra 0.15 pF never lands on the NAND2 at all. What the arrival prices instead is the repair: two cells where the typical run maps to one, doubling the area. An unbuffered gate at the heavy load models at about 127 ps, the recorded typical arrival plus the slope term, against about 234 ps recorded buffered: the model prices the repair's share at about 107 ps. Buffering made this path slower, with no rule violated, since 0.2 pF sits well under the 1.0 pF pin limit. The step cannot be switched off through this runner (abc -script is rejected, and excluding BUF cells crashes ABC in this build), so the unbuffered number stays a model estimate, not a recording.

    Delay against load

    The chart plots the fitted line at four loads: the two copied points, the typical load between them, and the heavy load past the table edge as extrapolated.

    Linear delay model through the two copied NAND2 points, with the typical load interpolated and the heavy load extrapolated. Delay rises from 0.08 ns at 0.01 pF to 0.1222 ns at 0.2 pF.

    Break it: refit at the slow slew

    The second program reruns the fit on the slow-slew row instead: 0.11 ns at 0.01 pF and 0.14 ns at 0.1 pF. The slope comes out half again as steep, so one line per slew is the honest unit, and the full table carries both axes for exactly this reason.

    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
    import sys
    
    # Copied exactly from the NAND2 cell_rise row at 0.1 ns input slew in sized.lib:
    # index_2 loads 0.01 and 0.1 pF give delays 0.11 and 0.14 ns.
    C0, D0 = 0.01, 0.11
    C1, D1 = 0.1, 0.14
    KS = (D1 - D0) / (C1 - C0)
    
    def model(c):
        return D0 + KS * (c - C0)
    
    checks = [
        (round(KS, 4), 0.3333),
        (round(model(0.05), 4), 0.1233),
        (round(model(0.2), 4), 0.1733),
    ]
    
    for i in range(len(checks)):
        got, want = checks[i]
        if got != want:
            print("FAIL: check " + str(i + 1) + " got " + str(got) + " want " + str(want))
            sys.exit(1)
    
    print("PASS: slow-slew slope 0.3333 ns per pF checked against the copied row")

    Common mistakes

    This model holds input slew fixed, so it understates every slow-input case. Quote a delay with its slew, and never trust the line past the last table load without saying extrapolated.

    Q: the load doubles. What happens to the delay?

    Weak answer: it doubles too. Strong answer: it rises by the slope times the added load only. From the copied row the slope is about 0.2222 ns per pF at the fast slew, so another 0.05 pF adds about 11 ps on top of an 80 ps base; doubling the load never doubles the delay because the base term does not scale. As a resistance the slope reads as about 222 ohms of effective drive: delay over load is resistance, the interview one-liner. The recorded runs move by more than the slope term only because the heavy run adds a repair stage the model never promised. Follow-up: when does the line stop being trustworthy? Past 0.1 pF, where the table ends, and at any slew other than the fitted one.

    Check yourself The copied fast-slew row gives 0.08 ns at 0.01 pF and 0.10 ns at 0.1 pF. What is the slope, and what does the model give at the typical 0.05 pF load?

    The 0.02 ns rise over the 0.09 pF span, worked out in the arithmetic above. At 0.05 pF the model gives 0.0889 ns, about 89 ps, and the Python checks replay exactly these digits.

    Check yourself The recorded arrivals differ by about 140 ps, but the model predicts only about 33 ps of that. Where does the rest come from?

    The buffer replaced the load instead of adding to it: the NAND2 now drives only the buffer's input pin, so its own stage delay falls rather than rising by the model's slope share. The arrival is slower anyway because the script's load-driven buffer step adds about 107 ps on the model here, with no rule violated: 0.2 pF is under the 1.0 pF limit, so this buffer is default buffering, not a rule fix.

    • Delay is a base plus slope times load; only the slope term scales.

    • The slope is about 0.22 ns per pF, about 222 ohms of effective drive: keep the units with it.

    • Past the last table load the line extrapolates and must say so.

    Rule of thumb: quote every delay with its input slew and its load, in pF.

    How this was checked

    Every number and picture on this page comes from one Yosys 0.69 run of the script shown plus two stdlib-only Python checks, recorded by the course checker (scripts/tools/run-rtl-testbenches.mjs with COURSE=synth): ABC maps one NAND2 under typical.constr and heavy.constr, inserting a buffer in the heavy run, and the programs replay the NAND2 rise rows copied exactly from sized.lib at fast and slow input slews. The unbuffered heavy-load arrival quoted on the page is a labelled model estimate, not a run: switching the buffer step off is not possible through the runner. The libraries are fictional teaching files, so the fitting method, not the digits, is the point.

    • Interview: run a mock interview on this topic

    Related topics

    • Buffer trees

    • Cell libraries and Liberty

    Previous

    33 / 139

    Next: Buffer Trees

    Up next

    Up nextBuffer Trees

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • Sizing, Cloning and Restructuring
    • Fanout Constraints in Practice