文件
phonerail/.claude/r2/d16_reach.py
T

95 行
4.6 KiB
Python
原始文件 Blame 文件历史

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
# -*- coding: utf-8 -*-
u"""D16:SDA6 / SCL6(CH224A ↔ TCA9548A 通道 5)为什么布不通 —— 在布线器同一张网格上做泛洪(服务器跑)。
DCDC_ROUTE_SERVER=1 /root/pypy/bin/pypy3 .claude/r2/d16_reach.py [NET ...] # 默认 SDA6 SCL6
障碍 = 板上快照(_board_for_nets.json)+ _d16_route.out.json 里本轮新增的铜,建图口径与 route_one 相同
(route_base._build:L1 西侧 12V 大铜挡线、PD_L1 窗口、NPTH / 天线净空、内层线挡孔)。
从本网每只焊盘的引出格点出发,两层 + 换层孔泛洪:报每只焊盘能到的格点数 / 外框、两头碰不碰得上;
碰不上时列出「围住它的那一圈」上是哪些网(格点归属),好决定拆谁、或者改原理图。
"""
import collections
import io
import json
import os
import sys
if os.environ.get('DCDC_ROUTE_SERVER') != '1':
sys.exit(u'!! 布线运算只在服务器上跑(DCDC_ROUTE_SERVER=1),见 CLAUDE.md')
if '--grid' not in sys.argv:
sys.argv += ['--grid', '0.125']
HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.dirname(HERE))
sys.path.insert(0, HERE)
import route_nets as N # noqa: E402
R = N.R
RT = R.RT
def main():
nets = [a for a in sys.argv[1:] if not a.startswith('--') and a not in ('0.125',)] or ['SDA6', 'SCL6']
b = json.load(io.open(os.path.join(HERE, '_board_for_nets.json'), encoding='utf-8'))
segs = [tuple(s[:7]) for s in b['segs']]
vias = [tuple(v[:3]) for v in b['vias']]
p = os.path.join(HERE, '_d16_route.out.json')
if os.path.exists(p):
r = json.load(io.open(p, encoding='utf-8'))
segs += [tuple(s[:7]) for s in r['segs']]
vias += [tuple(v[:3]) for v in r['vias']]
pads = R.load_pads()
N.INNER[:] = [s for s in segs if s[0] in (15, 16)]
obst = [s for s in segs if s[0] in (1, 2)]
w = 0.2
halfw = w / 2.0 + RT.CLR
g, gt, others = R.grid_now(pads, halfw, obst, vias, [])
inv = {v: k for k, v in g._id.items()} # router.Grid.nid:网名 → 1..250;255 = 多网争用
inv[255] = u'#多网'
out = {}
for net in nets:
ps = [q for q in pads if q[7] == net and not str(q[1]).endswith(R.TH_SUFFIX)]
regions = []
for q in ps:
starts = RT.pad_nodes(g, q, halfw, others.get(q[6], []), w / 2.0, gt)
seen = set()
dq = collections.deque()
for nd in starts:
n = (nd[0], nd[1], nd[2])
if g.free(n[0], n[1], n[2], net):
seen.add(n)
dq.append(n)
border = collections.Counter()
while dq:
l, i, j = dq.popleft()
for di, dj in ((1, 0), (-1, 0), (0, 1), (0, -1), (1, 1), (1, -1), (-1, 1), (-1, -1)):
n = (l, i + di, j + dj)
if n in seen:
continue
if g.free(l, i + di, j + dj, net):
seen.add(n)
dq.append(n)
elif 0 <= i + di < RT.NX and 0 <= j + dj < RT.NY:
border[(l, g.own[l][g.idx(i + di, j + dj)])] += 1
o = RT.LAY[1] if l == RT.LAY[0] else RT.LAY[0]
n = (o, i, j)
if n not in seen and g.free(o, i, j, net) and g.free_via(i, j, net):
seen.add(n)
dq.append(n)
xs = [RT.wx(n[1]) for n in seen]
ys = [RT.wy(n[2]) for n in seen]
box = (round(min(xs), 2), round(min(ys), 2), round(max(xs), 2), round(max(ys), 2)) if seen else None
top = [(l, inv.get(k, k), c) for (l, k), c in border.most_common(12)]
regions.append({'pad': '%s.%s' % (q[0], q[1]), 'starts': len(starts), 'cells': len(seen),
'box': box, 'border': top, 'set': seen})
print(u'%s %s.%s:引出格点 %d,能到 %d 格,外框 %s;边界上最多的归属 %s'
% (net, q[0], q[1], len(starts), len(seen), box, top[:8]))
meet = len(regions) >= 2 and bool(regions[0]['set'] & regions[1]['set'])
print(u'%s:两头%s' % (net, u'碰得上(该布得通,查 route_one)' if meet else u'碰不上 —— 一头被围死'))
out[net] = [{k: v for k, v in rg.items() if k != 'set'} for rg in regions] + [{'meet': meet}]
io.open(os.path.join(HERE, '_d16_reach.out.json'), 'w', encoding='utf-8').write(
json.dumps(out, ensure_ascii=False, default=str))
if __name__ == '__main__':
main()