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
      • What a Library Contains
      • Reading the Teaching Library
      • Delay Tables and Interpolation
      • Flops, Power, and Variants
      • Mapping Against the Library
    • Structuring and Buffering
  • 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

←Cell Libraries and Liberty
  1. Topics
  2. Logic Synthesis
  3. Logic Optimisation and Mapping
  4. Cell Libraries and Liberty
  5. Delay Tables and Interpolation
On this page

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

    Delay Tables and Interpolation

    Non-linear delay tables and bilinear interpolation with a runnable example.

    Real arrivals land between tabulated points, so every cell delay on a timed path is an interpolation. A transposed table corrupts all of them at once.

    After this lesson you can: run a bilinear lookup on the real NAND2 table, check it against hand arithmetic, and refuse an extrapolation.

    The question

    A delay table answers one question: this cell, this slew, this load, how long? Real arrivals land between tabulated points, so the tool interpolates. This lesson works the interpolation by hand on the real NAND2 table, then a runnable Python block replays it. Every value below is copied from values("0.08,0.1","0.11,0.14"), slew rows first.

    Two indexes, one orientation

    Each table has two indexes: input slew along the rows and output load along the columns. The teaching tables use 0.01 and 0.1 on both axes, in nanoseconds for slew and picofarads for load by the file header. A lookup inside the rectangle blends the four corners. A lookup outside it extrapolates: the runnable program below extends its bilinear weights past the edges, which is bilinear extrapolation, linear on each axis, the same math STA tools use. The real difference is what happens next: STA flags the max_transition and max_capacitance violation instead of trusting the number. Synthesis repairs slew and load with buffering and sizing so that every lookup lands back inside characterised ranges. Real Liberty tables run about seven by seven; these teaching tables stay two by two so the hand arithmetic fits on the page.

    Input slew (rows) / output load (cols)

    0.01

    0.1

    0.01

    0.08

    0.10

    0.1

    0.11

    0.14

    Fix the orientation first: slew 0.1 with load 0.01 is 0.11; slew 0.01 with load 0.1 is 0.10. The transposed reading swapped those two, and every midpoint built on them moved.

    Bilinear weights

    Bilinear interpolation weights the four corners by distance. The fractions fx and fy place the point: fx runs 0 to 1 across the slew rows, fy across the load columns. Each corner weight is one term per axis multiplied, the four always sum to one, and tabulated corners return their own entries exactly.

    The delay is the weighted sum. Work one edge first: at slew 0.055 and load 0.01, fx is a half and fy is 0, so the delay is half of 0.08 plus half of 0.11, which is 0.095 ns. That edge midpoint blends the two first-column corners at equal weight, one from each slew row.

    Diagram
    real NAND2 rise table (ns): T(0.01, 0.01) = 0.08, T(0.1, 0.01) = 0.11
    T(0.01, 0.1) = 0.10, T(0.1, 0.1) = 0.14
    edge point: slew = 0.055, load = 0.01
    fx = (0.055 - 0.01) / (0.1 - 0.01) = 0.045 / 0.09 = 0.5; fy = 0
    delay = 0.5 x 0.08 + 0.5 x 0.11 = 0.04 + 0.055 = 0.095 ns
    interior point: slew = 0.04, load = 0.04
    fx = (0.04 - 0.01) / 0.09 = 0.03 / 0.09 = 1/3; fy = 1/3
    delay = (4/9) x 0.08 + (2/9) x 0.11 + (2/9) x 0.10 + (1/9) x 0.14
          = 0.0355556 + 0.0244444 + 0.0222222 + 0.0155556
          = 0.0977778 ns = 22/225 ns

    A runnable lookup

    The program below embeds the real table as data and replays the hand arithmetic. Its five self-checks cover a corner, both edge midpoints, the interior point, and one point outside the table, passing only when every check lands within one part in a billion.

    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
    35
    36
    import sys
    
    # NAND2 cell_rise from course.lib, copied exactly:
    # index_1 (input_net_transition, rows): 0.01, 0.1
    # index_2 (total_output_net_capacitance, columns): 0.01, 0.1
    # values("0.08,0.1","0.11,0.14")
    SLEW = (0.01, 0.1)
    LOAD = (0.01, 0.1)
    TABLE = ((0.08, 0.10), (0.11, 0.14))
    
    def lookup(slew, load):
        (x0, x1), (y0, y1) = SLEW, LOAD
        fx = (slew - x0) / (x1 - x0)
        fy = (load - y0) / (y1 - y0)
        (t00, t01), (t10, t11) = TABLE
        return ((1.0 - fx) * (1.0 - fy) * t00 + fx * (1.0 - fy) * t10
                + (1.0 - fx) * fy * t01 + fx * fy * t11)
    
    def close(got, want):
        return abs(got - want) < 1e-9
    
    checks = [
        (lookup(0.01, 0.01), 0.08),
        (lookup(0.01, 0.055), 0.09),
        (lookup(0.055, 0.01), 0.095),
        (lookup(0.04, 0.04), 22.0 / 225.0),
        (lookup(0.2, 0.05), 13.09 / 81.0),
    ]
    
    for i in range(len(checks)):
        got, want = checks[i]
        if not close(got, want):
            print("FAIL: check " + str(i + 1) + " got " + str(got) + " want " + str(want))
            sys.exit(1)
    
    print("PASS: bilinear lookup matches hand arithmetic on 5 checks")

    The five checks climb in difficulty. The corner at slew 0.01 and load 0.01 must return 0.08 exactly, proving the copied data. The next two pin one fraction at a time: 0.09 across the fast-slew row, half of 0.08 plus half of 0.11 down the first load column. The fourth pins both fractions at once against 22/225 ns. The last check feeds slew 0.2 and expects the quotient the next section works by hand, pinning the extrapolation arithmetic.

    NAND2 rise delay against output load at input slew 0.01: 0.08 ns at 0.01 pF, 0.09 at 0.055 pF, 0.10 at 0.1 pF. Corner values copied from course.lib; the middle point is the verified lookup on this page.

    Break it: step outside the table

    Now feed the lookup slew 0.2, twice the slowest row of 0.1 (the fastest row is 0.01), at load 0.05. The fractions leave the unit square: fx is 19/9 and fy is 4/9. The weights still sum to one, but two turn negative, so corners subtract instead of blending. The program checks the result against 13.09/81, about 0.1616 ns.

    Diagram
    outside point: slew = 0.2, load = 0.05
    fx = (0.2 - 0.01) / 0.09 = 19/9; fy = (0.05 - 0.01) / 0.09 = 4/9
    weights: -50/81, 95/81, -40/81, 76/81 (still sum to 1)
    delay = (-50 x 0.08 + 95 x 0.11 - 40 x 0.10 + 76 x 0.14) / 81
          = (-4.0 + 10.45 - 4.0 + 10.64) / 81
          = 13.09 / 81 = 0.1616 ns (extrapolated, not characterised)

    Treat that number as a warning, not a measurement. Nothing characterises slew 0.2, so repair the slew first — buffer the net, upsize the driver — until every lookup lands back inside characterised ranges. Plausible extrapolation is still a guess with a formula.

    Predict first What delay does the lookup give at slew 0.2 and load 0.05, and should you trust it?

    13.09/81 ns from the hand arithmetic the program checks. Do not trust it: slew 0.2 sits past the slowest tabulated row at 0.1, two weights turn negative, and no characterised data backs the answer. Fix the slew until the lookup stays inside the table.

    Common mistakes

    Interpolating across a coarse grid hides curvature between corners. Trust the table only inside its index ranges, after slew and load are legal, and after checking that the orientation puts slew on the rows.

    Carrying a transposed table into a script. Two swapped corners move every midpoint: 0.10 read where 0.11 belongs drifts every blend built on it. Recheck values("0.08,0.1","0.11,0.14") string by string when results look mirrored.

    Set up a delay lookup by hand: slew 0.055, load 0.01 on the NAND2 table. Then say what breaks outside it.

    Weak answer: I average the four corners and use that everywhere. Outside the table I keep averaging.

    Strong answer: fx is 0.5 and fy is 0, so the delay is the edge midpoint the hand arithmetic checks, half of 0.08 plus half of 0.11. Outside the table the fractions leave the unit square, weights turn negative, and the slew-0.2 value is extrapolation with no characterised data behind it, so I repair the slew instead.

    Follow-up: the table grid doubles in each direction. How do you check a lookup implementation fast?

    Check yourself The table is read at slew 0.055 and load 0.01. What are fx, fy, and the delay?

    fx is 0.5 and fy is 0. The delay is 0.5 x 0.08 + 0.5 x 0.11, the edge midpoint the program checks as its third self-check.

    Check yourself Slew stays at 0.01 while load moves to 0.055. What does the lookup give, and why no new arithmetic?

    0.09 ns: fx is 0 and fy is 0.5, so it halves the two first-row corners 0.08 and 0.10. The program checks it as its second self-check.

    • Fractions fx and fy place the point; each corner weight is one term per axis and the four sum to one.

    • Inside the table the lookup blends; outside it weights turn negative and the answer is uncharacterised.

    • Repair slew and load until every lookup lands back inside characterised ranges.

    Rule of thumb: trust a table only inside its index ranges, after slew and load are legal.

    How this was checked

    No Yosys run on this page: table values are copied exactly from scripts/tools/synth-libs/course.lib, and the bilinear lookup is checked by the stdlib Python block shown (five self-checks: a corner, both edge midpoints, an interior point, and an extrapolation). The chart midpoint is hand arithmetic verified by that block. The seven-by-seven real-table size is a stated industry fact, not a recording.

    • Interview: run a mock interview on this topic

    Related topics

    • Flops, power, and variants

    • Cell Delay Models

    Previous

    29 / 139

    Next: Flops, Power, and Variants

    Up next

    Up nextFlops, Power, and Variants

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • What a Library Contains
    • Mapping Against the Library