Binary validation

Drive the original 1999 ASITIC binary headlessly and parse its output, so reASITIC’s numerical results can be compared to the ground truth.

The binary lives at ../run/asitic.linux.2.2 (relative to the reASITIC source tree). It is a 32-bit ELF that depends on the bundled libstdc++/Mesa/X11/readline shipped under ../run/libs/; running it requires a working X display (the binary --ngr flag does not fully bypass the X init). We use xvfb-run to provide a virtual display when one isn’t already available.

Notes on the legacy binary’s quirks:

  • The Ind / inductance commands segfault in headless mode on modern Linux (uninitialized table read at -4 offset, traced to cmd_inductance_compute reading g_metal_layer_table before it has been fully populated). We therefore validate numerical results against published Greenhouse / Grover formulas rather than against the binary’s Ind output. Geometry-only commands (Geom, MetArea, ListSegs, etc.) work and are the basis of binary-driven testing here.

  • When stdin closes the binary loops forever printing Unknown or Mistyped Commnd; therefore every script must end with a quit command (Q / QUIT / EXIT).

exception reasitic.validation.binary_runner.BinaryNotFoundError[source]

Bases: RuntimeError

Raised when the legacy asitic binary cannot be located.

class reasitic.validation.binary_runner.GeomResult[source]

Bases: object

Parsed output of the Geom <name> command.

name: str
kind: str
length_um: float | None = None
width_um: float | None = None
metal: str | None = None
total_length_um: float | None = None
total_area_um2: float | None = None
location: tuple[float, float] | None = None
n_segments: int | None = None
spiral_l1_um: float | None = None
spiral_l2_um: float | None = None
spiral_spacing_um: float | None = None
spiral_turns: float | None = None
raw: str = ''
__init__(name, kind, length_um=None, width_um=None, metal=None, total_length_um=None, total_area_um2=None, location=None, n_segments=None, spiral_l1_um=None, spiral_l2_um=None, spiral_spacing_um=None, spiral_turns=None, raw='')
Parameters:
Return type:

None

reasitic.validation.binary_runner.parse_geom_output(text)[source]

Parse the textual block emitted by Geom <name>.

Parameters:

text (str)

Return type:

GeomResult

class reasitic.validation.binary_runner.BinaryRunner[source]

Bases: object

Runs the legacy asitic binary under user-mode QEMU.

The 1999 ASITIC binary is a 32-bit i386 ELF linked against 1999-era libstdc++ / libreadline / Mesa libraries (bundled in run/libs/). Native execution on modern Linux works for geometry-only commands but segfaults inside compute_mutual_inductance (decomp 0x0804efb0) for any AC-frequency analysis (Res <freq>, Pi <freq>, 2Port, Eddy on). The crash is a 1999-era kernel/FPU-state ABI mismatch.

To make results reproducible across hosts, reASITIC’s validation harness only supports QEMU user-mode execution. Install qemu-user-static and the harness picks up qemu-i386-static automatically; set REASITIC_QEMU_USER to override the QEMU binary. If QEMU is not available, the runner construction raises BinaryNotFoundError and every test that depends on it auto-skips.

The parent asitic-re repo’s BINARY_VALIDATION.md documents how to install QEMU on each major distro and the legacy-Linux containerised path for full reproduction.

binary: Path
tech_file: Path
cwd: Path
qemu_user: str
timeout_s: float = 30.0
use_xvfb: bool = True
classmethod auto(tech_file='tek/BiCMOS.tek', timeout_s=30.0, qemu_user=None)[source]

Construct a runner using the legacy binary at run/asitic.

tech_file is resolved relative to the binary’s directory if not absolute. xvfb-run is auto-enabled when no DISPLAY is set on the host.

qemu_user is the QEMU binary used for translation (defaults to $REASITIC_QEMU_USER or "qemu-i386-static"). Raises BinaryNotFoundError when the QEMU binary isn’t on the PATH.

Parameters:
Return type:

BinaryRunner

run_script(script)[source]

Run script (newline-separated commands) and return stdout.

Parameters:

script (str)

Return type:

str

geom(build_command, name)[source]

Build name via build_command then run Geom <name>.

Example:

r = runner.geom(
    "W NAME=W1:LEN=100:WID=10:METAL=m3:XORG=0:YORG=0",
    "W1",
)
assert r.length_um == 100.0
Parameters:
  • build_command (str)

  • name (str)

Return type:

GeomResult

__init__(binary, tech_file, cwd, qemu_user, timeout_s=30.0, use_xvfb=True)
Parameters:
Return type:

None