Method and accuracy¶
What EMIR checks, where its currents come from, how exact the result is and how that is shown, and what EMIR leaves out. Screening, not sign-off.
What EMIR checks¶
A net is a resistor network: the extracted resistors of a DSPF. Currents enter and leave it at device pins and at the port where it is fed. EMIR takes the current in every branch and checks it against the process file:
| item | quantity | limits (process file) | unit |
|---|---|---|---|
| a wire segment | current per um of drawn width, I / W |
jmax_avg, jmax_rms (or jmax_rms_k), jmax_peak |
mA/um |
| a via array | its mean current per cut, I / cuts |
imax_avg, imax_rms, imax_peak |
mA/cut |
The ratio is the quantity over its limit. An item is FAIL at 1.00x and above, WARN
from warn_fraction (default 0.8), clean below; its worst metric is the governing
metric. A net is FAIL when any item fails. A ratio that is not a number (an unsolved
current) and a wire with no width (EMIR-E210) are FAIL by rule. A metric with no limit
in the process file is not checked, and every report lists it: EMIR never invents a
limit (SKY130 publishes no peak limits, so peak is not checked with pdks/sky130.yaml).
- avg, the time average, drives electromigration; rms measures self-heating;
peak guards against short high pulses. They are integrated with trapezoid
weights on the simulator's own time steps, over the record's last whole periods
(below). avg is exact for the samples joined by straight lines; rms is the trapezoid
of i squared, as
.meas RMStakes it (on a coarse record, a little high). - Currents that reverse: the magnitude of the signed average is compared with the DC limit, the least conservative reading of a bidirectional rule; the report lists under "Not checked" each branch whose average of |I| reaches the warn fraction while its signed average does not.
- A via's ratio is the array's mean per cut; the edge cuts carry more. A via above about 0.9x is listed as marginal.
- Temperature: the average limits hold at
em_tref(required), derated by ajmax_factortable or Black's equation (derating) at another analysis temperature (--em-temp); without either, a hotter analysis is not conservative and the run says so (EMIR-W315). Wire resistance is scaled by the TCRs for the IR drop. The rms limit is fixed (jmax_rms, a LEF's) or the self-heating formsqrt(jmax_rms_k x delta_T)with--delta-t(default 5 C). - IR drop is the largest drop from the net's feed (its
*|Pport, or--feed) to any node, device pins included, from the average currents; the dynamic IR drop is the largest instantaneous one. - Fix hints, at 1.00x and above: a wire at ratio r is widened to past W x r, to the
next 5 nm (
Metal1: widen 0.750 -> 1.255 um (x1.67)); a via with n cuts gets floor(n x r) + 1 cuts (Cont: 1 -> 2 cuts (+1)). They are first-order: re-extract and re-run after a fix.
Every run starts with the input checker (emir check runs it alone): a missing width,
an unmapped layer, a via with no cut count (checked as one cut, EMIR-W207), currents
that do not balance, a result that lacks a branch current. Each finding has a code and
the command that fixes it; a FAIL stops the run.
Where the currents come from¶
| currents | what you simulate | checks |
|---|---|---|
a simulation result (--cc-sim) |
the RC extraction itself, every resistor's current saved | every metric: avg, rms and peak EM, static and dynamic IR, from the simulated branch currents |
DC values (--currents, amps into the net) |
nothing | avg = rms = peak, each the DC current's magnitude, and the IR drop: a screen of your current budget |
--cc-sim (a name kept from 1.0) is the simulation result rcc reads; a run takes it or
--currents, never both (EMIR-E514). The window is the record's last whole periods of
--period (1e-08, 10n, 10NS), up to three, the ones closest to its end: rcc is
exact for the simulated record over the whole periods you give (--period); whether the
testbench has settled is yours to establish, as for any .meas. A transient needs
--period (EMIR-E428: EMIR never guesses one), and so does a --netlist run (nothing
is simulated without it); beyond that, EMIR refuses a run, with no number, only for what
it can check for certain:
EMIR-E431: fewer than two whole periods in the record (the message gives the stop time);EMIR-E429: the record's last two whole periods differ by more than 2 % in the average, rms or peak of a branch that matters, one carrying at least 1 % of its net's largest current (each change is a share of the larger of its two values, never of less than 10 % of that branch's own rms). Give the right--period, or simulate longer if the block is still starting up; a peak that differs on a coarse record wants a smaller maximum time step.
emir next plans the fix. A record held at DC (a bias) is a transient too: any --period
with two or more whole ones in the record gives the same numbers. An operating point (one
time point) needs no period: avg = rms = peak. EMIR measures the activity the testbench
drives: a load the record never exercises reads zero.
A simulated run is rcc. The testbench includes the RC extraction, and the simulator
saves the current of every resistor (emir save-lines writes those lines for Spectre,
HSPICE, Xyce or ngspice). EMIR reads every branch current: nothing is reconstructed,
and each segment's avg, rms and peak come from its own waveform. Walking a spanning tree
from the feed turns the branch currents into node voltages, so static and dynamic IR
come from the same result; each branch off the tree checks them again (the loop
residual, which catches a wrong DSPF, a missing save line or a flipped sign). The
voltages use the resistances the simulation ran, the DSPF's: the IR is the simulated
circuit's. When the EM limits are taken at another temperature (--em-temp),
EMIR-I407 says so; for IR at that temperature, extract or simulate at it.
--mode rcc is accepted and may be left out; any other value is a usage error
(EMIR-E507).
Big blocks need RCC in this release. The cost is the simulation: every resistor is
an element of the RC transient and its current one signal per time step, so on a block
the size of an ADC or PLL top the run is expected to be long and may converge poorly;
emir next plans it as a long run, for the person's go-ahead. A faster route for big
blocks (cc-grid: device currents solved through the R-only grid) and the chip-level
hierarchy are kept in the development repository (branch cc-grid-guard, not published)
for a later release.
Accuracy¶
rcc adds no model of its own: the currents are the simulator's, read one branch at a time. What it can add is the reduction to avg, rms and peak (the trapezoid rule on the simulator's time steps, over the window), and that is measured:
| evidence | what was compared | agreement |
|---|---|---|
examples/08_open_layout |
EMIR's avg, rms and peak on magic's SKY130 network (440 checked branches) against the simulator's own output, reduced without EMIR | 7.8e-13 |
| the same | EMIR's static and dynamic IR on out and vss against the simulator's own node voltages (the deck re-run printing them) | 3.2e-7 |
scripts/opensim_proof.py, DC loads |
example 02's rail, Xyce and ngspice, against the hand calculation | 1.3e-9 |
| the same, pulsed loads | against the hand calculation (the ramps of each pulse integrated by the trapezoid rule) | 2.8e-4 |
| the same, Xyce against ngspice | every ratio and IR drop, three load cases | 1.1e-4 |
emir validate |
six closed-form cases (below) | exact, or to the stated tolerance |
What remains is outside EMIR, and each report names it: the simulator's own tolerances and time steps; whether the testbench has settled over the periods you give (yours, as for any .meas); the extraction (a DSPF with series-reduced resistors averages a neck away); the limits (your process file's). DC currents are as good as the currents you give.
What a run produces¶
| output | how | for |
|---|---|---|
the run summary, emir.run/1 |
--format json, or --summary-out FILE |
agents and scripts; emir report reads it |
| the report | emir report --from FILE |
what an agent relays to a person |
| HTML | --html DIR |
an index of nets with the run's EM/IR chart, a page per net with a zoomable map |
| viewer data | --viewer DIR |
the Virtuoso Explorer and a KLayout marker database (emir.lyrdb) |
The summary's not_checked and the report's "Not checked" list what the run could not
judge: layers with no process entry, metrics with no limit, vias assumed to have one
cut, limits not derated to a hotter temperature, reversing currents. Relay it with the
verdict: a CLEAN net with half its layers unmapped is not clean.
Every chart uses one colour scale: blue below the warn fraction (by the ratio's log), amber in the warn band, red at 1x and over or not a number, grey where no limit is stated (not checked, never passed). The worst items are numbered on the map with their fixes.

The HTML report of examples/02_xyce (Xyce currents, illustrative limits).
Validation¶
| evidence | command | proves |
|---|---|---|
| the self-test | emir selftest |
this install works, offline, on the bundled sample (19 checks) |
| the analytic cases | emir validate |
6 cases with closed-form answers: a necked strap, the hand-entry forms (width loss, Black's derating), transient metrics on uneven time steps, the window, simulated branch currents through a result file into rcc, rcc and its loop residual |
| the simulators | emir verify-sim --sim <name> |
on your machine, that a simulator's route gives the hand-calculated currents (Simulators) |
| the examples | bash examples/<name>/run.sh |
each flow end to end against golden results (below) |
| the tests | pytest |
every feature, refusal code and fix, the agent contract, the leak guard |
The examples, with golden results¶
| example | runs | golden | proves |
|---|---|---|---|
02_xyce |
Xyce, rcc, on a rail worked out by hand | expected/summary.json |
rcc against the hand values (FAIL on a contact's peak, 1.04167x) |
03_ngspice |
the same circuit through ngspice | expected/summary.json |
the ngspice route; Xyce and ngspice agree |
06_supply_mesh |
a synthetic 10 x 10 supply mesh, Xyce, rcc, invented limits | expected/screen_n10.json, expected/screen_n10_no_period.json |
the four straps that fail at the feed, and their fixes; without --period, refused |
08_open_layout |
the magic route on a SKY130 NMOS array: rcc | expected/results.json |
rcc equals the simulator's own branch currents (7.8e-13) and node voltages (3.2e-7); without --period, refused |
09_cadence_flow |
the extraction plan, save lines and testbench, no Cadence tool | expected/summary.json |
what a Cadence site would run |
10_mcp_agent |
a scripted MCP client following emir_next |
expected/transcript.json, expected/tolerances.json |
the MCP server and the go-ahead refusal |
11_hspice_offline |
the HSPICE route on synthetic .tr0 and CSDF results |
expected/summary.json |
the HSPICE reader against the hand values |
What EMIR leaves out¶
- Sign-off and lifetime. No mission profile: screen each operating mode on its own.
- The limit model: one limit per layer and metric, with a width loss
(
I_max = J x (W - dW)) and a temperature derating. No limit tables by width range, no Blech length (no short wire is credited), no thermal map: one temperature per run. - Your inputs decide: the limits are your process file's (EMIR checks its form, not its values), the currents your simulation's, the geometry your extraction's.
- One feed per net (the net's first
*|Pport, or--feed), and one DSPF per run: no chip assembled from its blocks. - Text results only: binary formats are detected and refused, never guessed at.
- Tools: no licensed tool runs where EMIR is built, and none is claimed verified anywhere (Simulators, Cadence); Linux only. The examples are synthetic or illustrative: no real block has been screened in this repository.