Hardware accelerated flag checker 2
Extracting a netlist back out of a fabricatable SKY130 layout with no PDK installed.
NNS{fl4g_ver1f1ed_1n_SKY130_IC} Challenge
A follow-up to “Hardware accelerated flag checker 1”, now delivered not as an already-synthesized Verilog netlist but as physical VLSI layout files:
- flag_checker.gds (a self-contained GDSII layout, ~700 KB)
- flag_checker.mag (the same design in Magic VLSI’s native format)
Placed and routed for the SKY130A open-source PDK (sky130_fd_sc_hd standard cell library) using real fabricatable geometry (metal, vias, local interconnect) - this is what actually gets sent to a foundry, several abstraction levels below the RTL/gate netlist we got in challenge 1. The task is the same as before (“recover the flag it checks for”), but the netlist must first be extracted back out of the physical layout.
Why not Magic + the real PDK
The intended-looking path (open the layout in Magic VLSI with the sky130A
PDK installed, run extract to get a SPICE/gate netlist) needs Magic and
the multi-hundred-MB open_pdks sky130 install - neither available and
installing a full VLSI toolchain wasn’t practical here. Used the pip-
installable klayout Python bindings instead, which needed no external PDK
files: the GDS is self-contained (55 cells: the top design plus a full copy
of every standard-cell footprint’s geometry, since the flow that produced
it flattened the library cells’ physical views into the output GDS).
Approach
-
Netlist extraction from the layout only, no PDK. Sky130’s GDS layer map is public (li1.drawing=67/20, mcon=67/44, met1.drawing=68/20, via1=68/44, met2=69/20, … stepping by one layer number and datatype 44 per via level up to met5=72/20). Used KLayout’s
LayoutToNetlist: made aRegionper drawing/via layer,connect()’d same-layer regions and adjacent metal/via pairs, thenextract_netlist(). This produces, for free, oneCircuitper placed cell TYPE plus a top “flag_checker” circuit containing 855Subcircuitinstances (matching the .mag file’s 855use <cell> <inst>lines) connected by 164 top-level nets. -
Recovering pin names. Sky130 GDS cells carry their pin names as text labels on the
li1.labellayer (67/5) at each pin’s local coordinate (e.g.sky130_fd_sc_hd__nand2_2has “A”, “B”, “Y” labelled inside its own cell geometry). For every placed instance, read its cell type’s local pin-label positions once, then applied the instance’s placement transform (inst.trans) to get each pin’s absolute layout position, and calledLayoutToNetlist.probe_net(li1_region, point)to look up which extracted net that exact point belongs to - sidestepping KLayout’s automatic (and here unhelpful, single-anonymous-pin) hierarchical pin inference entirely. The same probing, using themet2.labellayer, recovered the 10 top-level I/O nets by name:character[0..6],clk,reset_n,found_flag(identical port names to challenge 1). -
Gate-level functional models. 854 instances break down into 5
dfxtp_2D-flip-flops (the state register, exactly as in challenge 1’s 5-bitsregister), ~27clkbuf/clkdlybuf4s25buffers (used here not just for clock distribution but also to buffer the character/reset_n inputs and the found_flag output - initially filtered these out as “clock tree only”, which silently broke the whole simulation since all 10 top-level ports actually terminate directly on one of these buffer cells), and ~122 real combinational standard cells across 40+ distinct types (a21oi, o31ai, and4b, o2111a, xnor2, …). Rather than hand-derive each cell’s boolean formula, fetched the officialsky130_fd_sc_hd__<cell>.functional.vVerilog models straight from the skywater-pdk-libs-sky130_fd_sc_hd GitHub repo - each one is a tiny, exact gate-primitive netlist (and/or/nor/nand/xnor/not/buf) with real pin names, which a small Python interpreter can execute directly. No guessing of the a21oi/o21ba/-style naming convention was needed. -
Simulating the FSM. With every instance’s pins mapped to net IDs and every cell type’s exact gate function known, wrote a worklist-based combinational evaluator: seed the 7 character bits, reset_n, and the 5 flip-flops’ current Q values as known net values, repeatedly evaluate any gate whose inputs are now all known, until the 5 D (next-state) nets and found_flag settle. This reproduces exactly the same style of automaton as challenge 1 (self-resetting on mismatch, folds back on a repeated flag-prefix character, found_flag asserts once state == 31).
-
Recovering the flag. Same walk as challenge 1: starting from the all-zero state, for each of the 95 printable ASCII candidate bytes 32-126, simulate one step; among the resulting states, keep the one that reaches a genuinely new (not-yet-visited) 5-bit state - resolves the forward-edge vs. KMP-failure-edge ambiguity the same way challenge 1’s netlist did. Repeating this 31 times (5-bit state space, 0..31) walks straight through the automaton and stops the moment found_flag=1.
Flag
NNS{fl4g_ver1f1ed_1n_SKY130_IC}