journal · 2026-04-28

Project 01 hardened — clean signoff on the first try

Project 01 hardened. 75 flow steps, ~50 seconds wall time once the PDK was cached, zero violations of any kind at signoff. Final GDS at projects/01_comb_logic/librelane/runs/RUN_2026-04-27_23-58-16/final/gds/top.gds, 271 KB, 60×60 μm die.

Getting here was the hard part

The harden was clean. Getting there took most of the evening:

  1. nix run github:librelane/librelane the first time pulled the Nix flake (~520 cache hits) and queued ~22 derivations to build locally — yosys-* plugins, verilator, openroad, magic, klayout, netgen, or-tools, the librelane Python package itself.
  2. First build failed. OpenROAD’s source tree copy hit “No space left on device” — / was at 100% with 1.5 GB free. It was using /tmp (tmpfs, 14 GB free) but the staging needed more.
  3. Relocated /nix to /mnt/MediaVolume/nix. rsynced 58 GB / 2.7M files / 76 K hardlinks across in 14 min, set up a bind mount via /etc/fstab. Wrote a paranoid one-shot script (/tmp/relocate-nix.sh) that tests the bind mount before touching fstab and rolls back on any failure.
  4. Second nix run with TMPDIR=/mnt/MediaVolume/nix-tmp finished cleanly. All EDA tools available.
  5. First harden attempt failed because my config.yaml used OpenLane-1 string syntax: DIE_AREA: "0 0 60 60". LibreLane v3 wants typed YAML lists: DIE_AREA: [0, 0, 60, 60].
  6. Third try worked. The PDK download (ciel pulling 7 sky130 tarballs, ~1 GB) finished in seconds because the nix run had primed the cache. Flow ran end-to-end.

Notable artifacts

Decision: leave the no-clock fallback unused

The original spec offered a fallback: “if pure combinational hardening is painful, wrap with a registered output.” It wasn’t painful. The warnings are noise, not errors, and the result is a clean GDS. Keeping the design pure-combinational. Project 02 will be the first sequential design.

Where we are now

Next: Project 02 (counter / PWM / LFSR). First real flops.

see also: project 01_comb_logic