Skip to content

Latest commit

 

History

History
215 lines (184 loc) · 12.3 KB

TECH_FILE.md

File metadata and controls

215 lines (184 loc) · 12.3 KB

Tech file reference

A tech file is a JSON document that tells Digital_Layout_Auto everything it needs to know about a PDK. The generators themselves contain no PDK data. ihp_sg13g2.json is a complete, working example for the open IHP SG13G2 PDK.

Keep tech files for proprietary PDKs out of version control. .gitignore already ignores local/ and tech/*.local.json; put them there.

What the PDK must provide

  • A std-cell LEF (macros with SIZE, signal pins drawn on one metal layer — the pin layer) and the matching GDS (one cell per macro, same names).
  • Three metal layers usable by the generators: the pin layer (usually metal 1), a vertical routing layer above it and a horizontal routing layer above that, plus the two vias between them.
  • Cells for the logic roles inv, nand2, nor2, nor3 and one or more fillers whose widths are multiples of the site. Rows abut with alternating R0/MX orientation and share their power rails, which must run along the full cell width on the pin layer.
  • Libraries that need separate well-tap cells are not supported yet.

Schema

{
  "name": "my_pdk",                       // used in messages and output headers
  "files": {
    "lef": ["${PDK_ROOT}/.../stdcell.lef"], // one or more LEF files (macros)
    "gds": "${PDK_ROOT}/.../stdcell.gds",
    "verilog": "${PDK_ROOT}/.../stdcell.v"  // optional, for your own simulations
  },
  "manufacturing_grid": 0.005,             // um
  "site": "CoreSite",                      // LEF SITE name, or [width, height] in um;
                                           // default: size of the smallest filler
  "power": {"vdd": "VDD", "vss": "VSS"},   // power / ground pin names in the LEF
  "grid": {                                // all optional
    "x_pitch": 0.48,                       // vertical-layer track pitch, default = site width
    "x_offset": 0.0,                       // track offset from the cell origin, default: auto
    "y_pitch": 0.50                        // horizontal grid pitch, default: derived from rules
  },
  "layers": {
    "pin":        {"lef": "Metal1", "gds": [8, 0],  "text": [8, 25],
                   "width": 0.16, "space": 0.18, "min_area": 0.09,
                   "wide_space": [[0.30, 1.0, 0.22]]},  // [width >=, parallel run >=, space]
    "vertical":   {"lef": "Metal2", "gds": [10, 0], "text": [10, 25], "width": 0.20, "space": 0.21, ...},
    "horizontal": {"lef": "Metal3", "gds": [30, 0], "text": [30, 25], "width": 0.20, "space": 0.21, ...},
    "via1": {"lef": "Via1", "gds": [19, 0], "size": 0.19, "space": 0.22,
             "enc_below": [0.01, 0.05],          // [side, end] enclosure, either orientation
             "enc_above": [0.005, 0.05]},
    "via2": {"lef": "Via2", "gds": [29, 0], "size": 0.19, "space": 0.22,
             "enc_below": [0.005, 0.05], "enc_above": [0.005, 0.05]},
    "boundary": [189, 4],                         // optional: placement boundary layer
    "via1_keepout": {"CONT": {"gds": [6, 0], "space": 0.1}}   // optional
  },
  "rules": {
    "via_stack": true,          // false: VIA2 may not sit on VIA1
    "via1_via2_space": 0.0,     // optional minimum VIA1-VIA2 distance
    "via1_obs_space": 0.22      // distance from VIA1-layer OBS in the LEF (default: via1 space)
  },
  "cells": {
    "inv":   "INV_CELL",                         // or {"cell": "...", "pins": {"A": "I", "Y": "ZN"}}
    "nand2": "NAND2_CELL",                       // logical pins A, B, Y
    "nor2":  "NOR2_CELL",
    "nor3":  "NOR3_CELL",                        // logical pins A, B, C, Y
    "fill":  ["FILL1", "FILL2", "FILL4"]
  }
}

Paths may use ${VAR} or ${VAR:-default}; relative paths are relative to the tech file. If a library's pin names differ from A/B/C/Y, give the mapping under pins.

What is derived automatically

  • Routing grid. Via pads are sized from the via size and the rectangular enclosure, oriented to fit the track pitch. The y pitch is the smallest value for which pads/wires of different nets on neighbouring grid nodes keep the layer spacing, so the router only has to track node ownership.
  • Pin access. For every signal pin a VIA1 position on a vertical-layer track is searched in the LEF geometry. If the pin metal is too narrow for the via enclosure, a small pin-layer patch is added when it keeps the pin-layer spacing to everything else in the cell.
  • Minimum area. Pin stubs on the vertical layer are lengthened to the layer's min_area, and their grid nodes are reserved accordingly.
  • Rails are read from the filler's power pins.

Run python gen.py --tech my_pdk.json decoder --bits 4 to see the derived grid ([tech] line) and check a first block.

Std-cell section (optional)

Needed only for python gen.py stdcell, which generates the library itself. It needs no LEF/GDS files: files and cells may be omitted when only the generator is used. Metal 1 rules come from layers.pin, the pin access pad from layers.via1, the track grid from grid.

"stdcell": {
  "row_height": 3.78, "site_width": 0.48, "site_name": "CoreSite",
  "rail_width": 0.44,                       // metal-1 power rail (centred on the cell edge)
  "layers": {"activ": [1, 0], "poly": [5, 0], "cont": [6, 0], "nwell": [31, 0],
             "pimp": [14, 0],               // p+ implant
             "nimp": null,                  // n+ implant layer if the PDK draws one
             "pin": [8, 2], "boundary": [189, 4]},
  "devices": {"nmos": "sg13_lv_nmos", "pmos": "sg13_lv_pmos",   // SPICE model names
              "l": 0.13, "wn": 0.74, "wp": 1.12},
  "rules": {
    "activ_width": 0.15, "activ_space": 0.21,
    "poly_width": 0.13, "poly_space": 0.18, "poly_endcap": 0.18, "poly_activ_space": 0.07,
    "cont_size": 0.16, "cont_space": 0.18, "cont_activ_enc": 0.07, "cont_poly_enc": 0.07,
    "cont_gate_space": 0.11, "polycont_activ_space": 0.14, "m1_cont_enc": [0.0, 0.05],
    "nwell_enc_pdiff": 0.31, "nwell_space_ndiff": 0.31, "nwell_enc_ntap": 0.24, "nwell_space_ptap": 0.24,
    "pimp_enc_pdiff": 0.18, "pimp_space_ndiff": 0.18, "pimp_enc_ptap": 0.03, "pimp_space_ntap": 0.03,
    "pimp_enc_gate": 0.30, "pimp_space_gate": 0.30, "pimp_cont_space": 0.09
  }
}

If layers.via1_keepout names the contact layer, the generator keeps every pin access via that far from contacts, puts the tap contacts halfway between vertical-layer tracks (so power-strap vias on the rails clear them) and reports all contacts as VIA1 obstructions in the LEF.

The run prints the derived template ([std ] line: band positions, n-well edge, poly-contact window, gate pitches) and fails early if the row height cannot hold wn / wp. It writes <lib>.tech.json, a copy of the tech file pointing at the new LEF/GDS with the inv/nand2/nor2/nor3/fill roles filled in.

SRAM section (optional)

Needed only for python gen.py sram. It sits at the top level (or inside stdcell):

"sram": {"min_nmos_width": 0.15, "min_pmos_width": 0.15, "cr": 1.5, "pr": 1.0}   // "l" optional
  • min_nmos_width / min_pmos_width: smallest legal transistor channel width (default stdcell.rules.activ_width). They can be larger than the active width rule: NSPL05 has activ_width 0.7 but rule 2.ACT.W1 needs a channel width of 1.6.
  • cr (cell ratio W_PD/W_PG, minimum) and pr (pull-up ratio W_PU/W_PG, maximum): defaults for --cr / --pr. l overrides the gate length (default stdcell.devices.l).

The sizer finds the minimum legal quantized widths (W_PU, W_PG, W_PD) that satisfy the CR / PR targets and the single-contact / minimum-width floors; it is not a delay or power optimum. cr, pr, v_read, v_write and the snm_* / write_margin_factor figures ("model": "heuristic_ratio" in the JSON metrics) come from a fixed-MU_P (0.4) / fixed-VM (0.5) first-order resistive-divider heuristic ratio model. They are not PDK MOS-model results: true SNM, write margin, delay and power need SPICE simulation with the PDK device models.

The generator also reads layers.vertical (M2), layers.horizontal (M3), layers.via2, rules.via_stack, rules.via1_via2_space and layers.via1_keepout (see above) to draw the bit lines (M2), word lines (M3) and the power straps. The array needs the stdcell section but no LEF/GDS files.

SPICE section (optional)

Every key is optional; without the section generation is unchanged and simulation is reported as unavailable (never faked). It sits at the top level of the tech file:

"spice": {
  "includes": [                                     // device model files, in order
    {"file": "${PDK_ROOT}/models/corner.lib", "section": "tt"},   // -> .lib "<file>" tt
    "${PDK_ROOT}/models/extra.mod"                                // -> .include "<file>"
  ],
  "cell_library": ["${PDK_ROOT}/cells/stdcell.cdl"],// SPICE/CDL .SUBCKTs of the LEF cells (structural block netlists)
  "vdd": 1.2,                                       // supply voltage in volts (number or SPICE string like "3.3")
  "temperature": 27,                                // deg C, emitted as .temp
  "corner": "tt",                                   // free text; recorded in the metadata/drawings
  "testbench": {                                    // all optional
    "max_vectors": 24,                              // decoder: input vectors simulated (default 24)
    "high_fraction": 0.9, "low_fraction": 0.1,      // logic levels as a fraction of VDD (defaults 0.9 / 0.1)
    "edge": "0.1n", "load": "10f"                   // BOTH set -> also measure delay arcs of generated cells
  }
}
  • Paths follow the same rules as files: ${VAR} / ${VAR:-default}, relative to the tech file. Do not commit proprietary paths or models: use ${PDK_ROOT}-style variables or an ignored local/ file.
  • includes + vdd are what a simulation needs. Models are never guessed: an unset variable, a missing file or a missing vdd is reported (simulation.status = "unavailable" plus the reason).
  • cell_library supplies the real sub-circuits for decoder/block netlists. python gen.py stdcell writes it into the generated <lib>.tech.json automatically (and carries over includes, re-based relative to the new file), so blocks built from generated cells get structural SPICE without extra setup.
  • testbench.edge is the full 0-100 % ramp time of the input, load the output capacitance (farads); delay is measured 50 % -> 50 %. They are testbench conditions you choose, recorded in the results.
  • The device model names in stdcell.devices (nmos, pmos) must exist in the included model files.

What is produced and how it is judged

artifact <name>.spice.json schematic SVG --simulate checks (DC, real models)
stdcell cells, functions, device counts <lib>_schematics.svg + schematics/<cell>.svg every input vector of every logic cell reaches the logic level (+ delay arcs if edge/load)
decoder block ports, instance count <name>_schematic.svg addressed output high, others low, for up to max_vectors vectors
sram rows/cols, sizing <name>_schematic.svg, <name>_bitcell_schematic.svg 6T bit-cell hold 0/1, read 0/1 (no flip, read bump measured), write 0/1

Metadata JSON ("schema": "dla-spice-metadata/1") holds provenance (generator version, tech name, SHA-256 of the tech and model files), the configured includes/corner/VDD/temperature, sub-circuit and device counts, top pins and supplies, and simulation: requested (off|auto|require), status (not_requested|unavailable|passed|failed), reason, simulator command, deck/log paths, checks, measurements (value + unit) and delays. Values only appear when a simulator produced them.

Policy (gen.py --simulate, SpiceOptions)

mode not configured / no simulator check fails or simulator errors
off (default) nothing runs –
auto recorded as unavailable with the reason, exit code 0 failed, exit code 1
require unavailable, exit code 1 failed, exit code 1

The simulator is --spice-cmd, else $DLA_SPICE, else ngspice/ngspice_con on PATH (see dla.spice). The bit-cell checks are DC state checks (.nodeset selects the stored state; a write succeeds when the old state is no longer a DC solution); they are not SNM, write-margin, timing or power characterisation.