← Commit history

Delete design/gen/route_all.py

John Lauer ·203d5abd7a ·7d ago ·parent ed69441
1 file changed −275
design/gen/route_all.pydeleted−275
@@ -1,275 +0,0 @@-#!/usr/bin/env python3-"""Assemble every route: high-speed (hs.py), fixed extras, maze-routed low-speed nets, GND fan-out, stitching,-zones and keepouts -> design/routes.json for build_board.py final."""-import json, math, os, sys, time-import numpy as np-from shapely.geometry import Polygon, Point, LineString, box-from shapely.ops import unary_union-from shapely import contains_xy-sys.path.insert(0, os.path.dirname(__file__))-import hs, maze-from maze import G, NX, NY, LI--ROOT = os.path.join(os.path.dirname(__file__), "..")-pads = json.load(open(os.path.join(ROOT, "design", "pads.json")))-lay = json.load(open(os.path.join(ROOT, "design", "layout.json")))-nl = json.load(open(os.path.join(ROOT, "design", "netlist.json")))-OUTLINE = Polygon(lay["outline"])-LAYMAP = {"F.Cu": "L1", "In2.Cu": "L3", "In4.Cu": "L5", "B.Cu": "L6"}--T, V = [], []           # all tracks and vias for routes.json-B = maze.Board()--# ------------------------------------------------------------------ fixed high-speed copper-pairs, lines = hs.all_routes()-for p in pairs:-    for t in p.tracks:-        T.append(t); B.track(*t, hs=True)-    for v in p.vias:-        V.append(v); B.via(v[0], v[1], v[2], v[3], hs=True)-for l in lines:-    for t in l.tracks:-        T.append(t); B.track(*t)-    for v in l.vias:-        V.append(v); B.via(v[0], v[1], v[2], v[3])--# ------------------------------------------------------------------ pads-PAD = {}-for p in pads:-    net = p["net"] or f"NC:{p['ref']}.{p['num']}"-    PAD[(p["ref"], p["num"], round(p["x"], 3), round(p["y"], 3))] = p-    geom = unary_union([Polygon(o) for o in p["poly"] if len(o) >= 3]) if p["poly"] else Point(p["x"], p["y"]).buffer(p["w"] / 2)-    p["geom"] = geom-    lis = [LI[LAYMAP[l]] for l in p["layers"] if l in LAYMAP]-    if len(p["layers"]) >= 6 or p["drill"][0] > 0:-        lis = [0, 1, 2, 3]-        # a plated hole occupies every layer with at least its drill-        dg = Point(p["x"], p["y"]).buffer(max(p["drill"]) / 2 + 0.05)-        p["geom"] = geom.union(dg)-    B.paint_geom(lis, p["geom"], B.nid(net))-    p["lis"] = lis--# ------------------------------------------------------------------ fixed extras-def add_track(t):-    T.append(t); B.track(*t)--def add_via(v, hsflag=False):-    V.append(v); B.via(v[0], v[1], v[2], v[3], hs=hsflag)--pin_net = {}-for n, ps in nl["nets"].items():-    for q in ps:-        pin_net[q] = n-# GND gold fingers: short stub off the inner end so the outer-layer GND pour picks them up-for p in pads:-    if p["ref"] == "J1" and p["net"] == "GND":-        layer = "L1" if "F.Cu" in p["layers"] else "L6"-        add_track((layer, "GND", p["x"], hs.PAD_TOP, p["x"], hs.PAD_TOP - 0.55, 0.3))-cols = {}-for p in pads:-    if p["ref"] == "J1":-        cols.setdefault(round(p["x"], 3), {})["F" if "F.Cu" in p["layers"] else "B"] = p["net"]-for x, sides in sorted(cols.items()):-    if sides.get("F") == "GND" and sides.get("B") == "GND":-        add_via((x, hs.PAD_TOP - 0.62, "GND", 0.4, 0.2))-# +12V fingers B1..B6: one bar-b1 = hs.finger("B1"); b6 = hs.finger("B6")-add_track(("L1", "+12V_EDGE", b1[0], b1[1], b1[0], 111.6, 0.3))-for n in range(2, 7):-    x, y = hs.finger(f"B{n}")-    add_track(("L1", "+12V_EDGE", x, y, x, 111.6, 0.3))-add_track(("L1", "+12V_EDGE", b1[0], 111.6, b6[0], 111.6, 0.3))-# OCuLink GND pads: via-in-pad (filled and capped)-for p in pads:-    if p["ref"] in ("J2", "J3", "J4", "J5") and p["net"] == "GND" and p["num"] != "SH":-        add_via((p["x"], p["y"], "GND", hs.VIP_D, hs.VIP_H), True)--# ------------------------------------------------------------------ finger escape reservations-# every used signal/power finger keeps a 2.4 mm column above it on its own layer, so no other net's via lands there-HS_NETS = set()-for _p in pairs:-    HS_NETS |= {_p.nnet, _p.pnet}-for p in pads:-    if p["ref"] != "J1" or not p["net"] or p["net"] in ("GND", "+12V_EDGE") or p["net"] in HS_NETS:-        continue-    li = LI["L1"] if "F.Cu" in p["layers"] else LI["L6"]-    w = 0.2-    B.paint_geom(li, box(p["x"] - w / 2, hs.PAD_TOP - 2.4, p["x"] + w / 2, hs.PAD_TOP), B.nid(p["net"]))--# ------------------------------------------------------------------ static keepouts-yy, xx = B.Y, B.X-inside = contains_xy(OUTLINE.buffer(-0.42), xx, yy)-for li in range(4):-    B.block[li] |= ~inside-# long-edge strips: no copper on outer layers within 2.75 mm, inner layers within 1.0 mm (OCP Fig. 8/10)-strip_outer = (xx < 2.75) | (xx > 76 - 2.75)-strip_inner = (xx < 1.0) | (xx > 75.0)-B.block[LI["L1"]] |= strip_outer; B.block[LI["L6"]] |= strip_outer-B.block[LI["L3"]] |= strip_inner; B.block[LI["L5"]] |= strip_inner-# gold-finger field: nothing else on the outer layers past the finger tops; inner copper clear of the bevel-B.block[LI["L1"]] |= yy > 112.05-B.block[LI["L6"]] |= yy > 112.05-B.block[LI["L3"]] |= yy > 113.6-B.block[LI["L5"]] |= yy > 113.6-B.block_via = np.zeros_like(B.block)-for li in range(4):-    B.block_via[li] = B.block[li] | (yy > 111.6)---def terminals(net):-    out = []-    for p in pads:-        if p["net"] != net:-            continue-        cells = set()-        x0, y0, x1, y1 = p["geom"].bounds-        i0, i1, j0, j1 = int(x0 / G), int(x1 / G) + 1, int(y0 / G), int(y1 / G) + 1-        sub = contains_xy(p["geom"].buffer(-0.02), xx[j0:j1 + 1, i0:i1 + 1], yy[j0:j1 + 1, i0:i1 + 1])-        js, iss = np.nonzero(sub)-        for li in p["lis"]:-            for j, i in zip(js + j0, iss + i0):-                cells.add((li, int(j), int(i)))-        if not cells:-            cells = {(li, int(round(p["y"] / G)), int(round(p["x"] / G))) for li in p["lis"]}-        out.append(cells)-    # existing copper of the net (fixed lines) is one more terminal-    nid = B.nid(net)-    ex = set()-    for (lay_, n, x1, y1, x2, y2, w) in T:-        if n == net:-            L = max(1, int(math.hypot(x2 - x1, y2 - y1) / G))-            for k in range(L + 1):-                x = x1 + (x2 - x1) * k / L; y = y1 + (y2 - y1) * k / L-                ex.add((LI[lay_], int(round(y / G)), int(round(x / G))))-    if ex:-        out.insert(0, ex)-    return out---L6_REGION = (yy > 101.0) & (xx < 30.0)-ROUTE = [-    # bottom-side (A) finger escapes first: each needs a via site above its own finger-    ("PERST1#", 0.15, ("L1", "L3", "L5", "L6")), ("PRSNTA0#", 0.15, ("L1", "L3", "L6")),-    ("PRSNTB2#", 0.15, ("L1", "L3", "L6")), ("SMCLK0", 0.15, ("L1", "L3", "L5", "L6")),-    ("SMDAT0", 0.15, ("L1", "L3", "L5", "L6")), ("PERST2#", 0.15, ("L1", "L3", "L5", "L6")),-    ("PERST3#", 0.15, ("L1", "L3", "L5", "L6")), ("WAKE0#", 0.15, ("L1", "L3", "L5", "L6")),-    ("SLOT_ID1", 0.15, ("L1", "L3", "L5", "L6")),-    # top side and power-    ("+3V3_EDGE", 0.2, ("L1", "L3", "L5")), ("+12V_EDGE", 0.2, ("L1", "L3", "L5")),-    ("PRSNTB3#", 0.15, ("L1", "L3")), ("PERST0#", 0.15, ("L1", "L3", "L5")),-    ("NIC_PWR_GOOD0", 0.15, ("L1", "L3", "L5")), ("SCAN0_LD#", 0.15, ("L1", "L3", "L5")),-    ("SCAN0_DATA_IN", 0.15, ("L1", "L3", "L5")), ("SCAN0_DATA_OUT", 0.15, ("L1", "L3", "L5")),-    ("SCAN0_CLK", 0.15, ("L1", "L3", "L5")), ("SLOT_ID0", 0.15, ("L1", "L3", "L5")),-    ("AUX_PWR_EN0", 0.15, ("L1", "L3", "L5")),-    ("PERST0_BUF", 0.15, ("L1", "L3", "L5")), ("PERST1_BUF", 0.15, ("L1", "L3", "L5")),-    ("PERST2_BUF", 0.15, ("L1", "L3", "L5")), ("PERST3_BUF", 0.15, ("L1", "L3", "L5")),-    ("PORT0_PERST#", 0.15, ("L1", "L3", "L5")), ("PORT1_PERST#", 0.15, ("L1", "L3", "L5")),-    ("PORT2_PERST#", 0.15, ("L1", "L3", "L5")), ("PORT3_PERST#", 0.15, ("L1", "L3", "L5")),-    ("PORT0_CPRSNT#", 0.15, ("L1", "L3", "L5")), ("PORT1_CPRSNT#", 0.15, ("L1", "L3", "L5")),-    ("PORT2_CPRSNT#", 0.15, ("L1", "L3", "L5")), ("PORT3_CPRSNT#", 0.15, ("L1", "L3", "L5")),-    ("FRU_WP", 0.15, ("L1", "L3", "L5")), ("SR0_SER", 0.15, ("L1", "L3", "L5")),-    ("LED3V3_A", 0.15, ("L1",)), ("LED12V_A", 0.15, ("L1",)),-]--CLR, CLR_HS = 0.14, 0.28---def paint_net(net, tracks, vias):-    for t in tracks:-        B.track(*t)-    for v in vias:-        B.via(v[0], v[1], v[2], v[3])---def route_list(order, routed, attempt_log):-    fails = []-    for (net, w, allow) in order:-        terms = terminals(net)-        if len(terms) < 2:-            continue-        paths, msg = maze.route_net(B, net, terms, w=w, clr=CLR, clr_hs=CLR_HS, allow=allow, l6_region=L6_REGION)-        if paths is None:-            fails.append(net); attempt_log.append(f"FAIL {net}: {msg}"); print(f"FAIL {net}: {msg}", flush=True); continue-        tr, vi = [], []-        for pth in paths:-            a_, b_ = maze.path_to_copper(pth, net, w)-            tr += a_; vi += b_-        routed[net] = (tr, vi)-        paint_net(net, tr, vi)-        print(f"{net}: {len(paths)} branch(es), {len(tr)} tracks, {len(vi)} vias", flush=True)-    return fails---def rebuild(routed):-    """Fresh raster with fixed copper + pads + reservations + everything routed so far."""-    global B-    lab0, hs0, blk, blkv = BASE-    B.lab = lab0.copy(); B.hs = hs0.copy()-    for net, (tr, vi) in routed.items():-        paint_net(net, tr, vi)---if __name__ == "__main__":-    t0 = time.time()-    FIXED_T, FIXED_V = list(T), list(V)-    BASE = (B.lab.copy(), B.hs.copy(), B.block.copy(), B.block_via.copy())-    W = {n: (w, a) for (n, w, a) in ROUTE}-    routed = {}-    log = []-    fails = route_list(ROUTE, routed, log)-    priority = []                      # every net that ever failed, routed first from then on-    for rnd in range(10):-        if not fails:-            break-        for n in fails:-            if n not in priority:-                priority.append(n)-        print(f"--- rip-up round {rnd+1}: {fails}  priority {priority}", flush=True)-        rip = set()-        for net in priority:-            for (li, j, i) in set().union(*terminals(net)):-                r = int(1.2 / G)-                for lj in range(4):-                    blk = B.lab[lj, max(0, j - r):j + r + 1, max(0, i - r):i + r + 1]-                    for nid in np.unique(blk):-                        if nid >= 0 and B.netname[nid] in routed:-                            rip.add(B.netname[nid])-        rip |= set(priority)-        for n in rip:-            routed.pop(n, None)-        rebuild(routed)-        # the nets that just failed get first pick, then the older failures, then the ripped-up rest-        first = list(fails) + [n for n in priority if n not in fails]-        order = [(n, *W[n]) for n in first] + [(n, *W[n]) for n in [x[0] for x in ROUTE] if n in rip and n not in priority]-        fails = route_list(order, routed, log)-    # ESD grounds: each ESD's GND pins to the GND pads of its connector-    for k in range(4):-        ref, conn = f"U{5+k}", f"J{2+k}"-        esd_cells, conn_cells = [], set()-        for p in pads:-            if p["net"] != "GND":-                continue-            if p["ref"] == ref or (p["ref"] == conn and p["num"] in ("B11", "B14", "B17", "B20")):-                x0, y0, x1, y1 = p["geom"].bounds-                i0, i1, j0, j1 = int(x0 / G), int(x1 / G) + 1, int(y0 / G), int(y1 / G) + 1-                sub = contains_xy(p["geom"].buffer(-0.02), xx[j0:j1 + 1, i0:i1 + 1], yy[j0:j1 + 1, i0:i1 + 1])-                js, iss = np.nonzero(sub)-                cells = {(LI["L1"], int(j + j0), int(i + i0)) for j, i in zip(js, iss)}-                if p["ref"] == ref:-                    esd_cells.append(cells)-                else:-                    conn_cells |= cells-        terms = [conn_cells] + esd_cells-        paths, msg = maze.route_net(B, "GND", terms, w=0.2, clr=CLR, clr_hs=CLR_HS, allow=("L1",))-        if paths is None:-            print(f"FAIL ESD GND {ref}: {msg}"); fails.append(f"GND:{ref}"); continue-        tr, vi = [], []-        for pth in paths:-            a_, b_ = maze.path_to_copper(pth, "GND", 0.2); tr += a_; vi += b_-        routed[f"GND:{ref}"] = (tr, vi); paint_net("GND", tr, vi)-        print(f"GND {ref}: {len(tr)} tracks")-    for net, (tr, vi) in routed.items():-        T.extend(tr); V.extend(vi)-    json.dump({"tracks": T, "vias": V, "fails": fails, "fixed_tracks": FIXED_T, "fixed_vias": FIXED_V},-              open(os.path.join(ROOT, "design", "routes_ls.json"), "w"))-    print("fails:", fails, f"[{time.time()-t0:.0f}s]")