R2:底板 / 刀片布局布线脚本、快照、截图与规划文档更新(含外壳、打印件、布线归档)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
这个提交包含在:
+128
@@ -0,0 +1,128 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
u"""服务器上一次做完「剩 3 只被围死的脚」(2026-09-11 混合布线收尾,用户选「拆邻线重排」):
|
||||
|
||||
DCDC_ROUTE_SERVER=1 /root/pypy/bin/pypy3 .claude/r2/fix3.py [--fence-y1 35.0]
|
||||
读 _board_for_nets.json(板上快照)+ _base_preroute_0911.json(UP 两端预布段 / 孔),写 _fix3.out.json
|
||||
|
||||
1. UP 中心线重布(up_route.route_centerline,pitch 0.52),L1 上 J37 北排上方加禁区 (48, 33.0)~(62, FENCE_Y1):
|
||||
UP 在这一段北移,给 J37.19 的 +5V 留出沿北排焊盘顶上走到 J37.32 的带子。障碍 = 板上除 UP 以外的全部铜。
|
||||
2. 板面数据里的 UP 换成新 UP(+ 预布两端段 / 孔)。
|
||||
3. 拆 U32 南 / 西南区的 strap 网(全是自动布线的短线)。
|
||||
4. 按序补:+5V(J37.19)→ +3V3_HUB(C744.1 那块)→ CFGSEL0 → 拆掉的 strap 网(route_nets 的连通块 + 代表焊盘 + route_one)。
|
||||
输出:新 UP、各网新增线 / 孔、被拆的网、每个网布前 / 布后的连通块数。本机拿去离线复核后再删旧加新。
|
||||
"""
|
||||
import io
|
||||
import json
|
||||
import math
|
||||
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_base as R # noqa: E402
|
||||
import up_route as UPR # noqa: E402
|
||||
import route_nets as RN # noqa: E402
|
||||
|
||||
RT = R.RT
|
||||
UP = ('UP_DP', 'UP_DM')
|
||||
RIP = ['$4N596', '$4N597', '$4N598', '$4N602', '$4N603', 'CFGSEL1', 'NONREM0', 'NONREM1', 'VBUS_DET']
|
||||
ORDER = [('+5V', 0.3), ('+3V3_HUB', 0.2), ('CFGSEL0', 0.15)] + [(n, 0.15) for n in RIP]
|
||||
FENCE_Y1 = float(sys.argv[sys.argv.index('--fence-y1') + 1]) if '--fence-y1' in sys.argv else 35.0
|
||||
L = lambda s: math.hypot(s[3] - s[1], s[4] - s[2]) # noqa: E731
|
||||
|
||||
|
||||
def main():
|
||||
board = json.load(io.open(os.path.join(HERE, '_board_for_nets.json'), encoding='utf-8'))
|
||||
pre = json.load(io.open(os.path.join(HERE, '_base_preroute_0911.json'), encoding='utf-8'))
|
||||
pads = R.load_pads()
|
||||
logs = []
|
||||
seg_all = [tuple(s[:7]) for s in board['segs']]
|
||||
via_all = [tuple(v[:3]) for v in board['vias']]
|
||||
if '--no-up' in sys.argv:
|
||||
# UP 不动(整板障碍下中心线找不到通道,2026-09-11 两种禁区都失败):只拆 strap 网、按序补
|
||||
# --rip A,B,... 只拆这些网(默认 RIP 全拆);--order A,B,... 补网顺序(默认 +3V3_HUB → CFGSEL0 → 拆掉的网)
|
||||
rip = sys.argv[sys.argv.index('--rip') + 1].split(',') if '--rip' in sys.argv else list(RIP)
|
||||
wid = dict(ORDER)
|
||||
if '--order' in sys.argv:
|
||||
order = [(n, wid.get(n, 0.15)) for n in sys.argv[sys.argv.index('--order') + 1].split(',')]
|
||||
else:
|
||||
order = [('+3V3_HUB', 0.2), ('CFGSEL0', 0.15)] + [(n, 0.15) for n in rip]
|
||||
segs = [s for s in seg_all if s[6] not in rip]
|
||||
vias = [v for v in via_all if v[2] not in rip]
|
||||
print(u'拆:%s;顺序:%s' % (' '.join(rip), ' '.join(n for n, _w in order)))
|
||||
out = {}
|
||||
for net, w in order:
|
||||
groups = RN.components(net, pads, segs, vias)
|
||||
if len(groups) < 2:
|
||||
print(u'%-9s 已连通,跳过' % net)
|
||||
continue
|
||||
lg = []
|
||||
s, v = R.route_one(net, RN.reps(groups), w, pads, [x for x in segs if x[0] in (1, 2)], vias, [], lg)
|
||||
segs += [tuple(x) for x in s]
|
||||
vias += [tuple(x) for x in v]
|
||||
after = len(RN.components(net, pads, segs, vias))
|
||||
out[net] = {'segs': [list(x) for x in s], 'vias': [list(x) for x in v], 'before': len(groups), 'after': after}
|
||||
print(u'%-9s %d 块 → %d 块;新增 %d 段 %.1f mm / %d 孔(线宽 %.2f)%s'
|
||||
% (net, len(groups), after, len(s), sum(L(x) for x in s), len(v), w, (u';' + ';'.join(lg)) if lg else ''))
|
||||
bad = [n for n, o in out.items() if o['after'] > 1]
|
||||
print(u'仍断开:%s' % (' '.join(bad) or u'无'))
|
||||
io.open(os.path.join(HERE, '_fix3.out.json'), 'w', encoding='utf-8').write(json.dumps(
|
||||
{'ok': True, 'up_new': None, 'rip': rip, 'order': [n for n, _w in order], 'nets': out, 'bad': bad},
|
||||
ensure_ascii=False))
|
||||
return
|
||||
# ── 1. UP 中心线重布(障碍 = 板上除 UP 以外的铜)
|
||||
obs_s = [s for s in seg_all if s[0] in (1, 2) and s[6] not in UP]
|
||||
obs_v = [v for v in via_all if v[2] not in UP]
|
||||
UPR.PITCH = 0.52
|
||||
UPR.EXTRA_FENCE = [(1, (48.0, 33.0, 62.0, FENCE_Y1))]
|
||||
pad_pen, layer_dir = RT.PAD_PEN, RT.LAYER_DIR
|
||||
RT.PAD_PEN, RT.LAYER_DIR = R.DP_PAD_PEN, {}
|
||||
try:
|
||||
up_new, _ = UPR.route_centerline(pads, obs_s, obs_v, pre, logs)
|
||||
finally:
|
||||
RT.PAD_PEN, RT.LAYER_DIR = pad_pen, layer_dir
|
||||
if not up_new:
|
||||
print(u'UP 中心线重布失败:%s' % logs)
|
||||
io.open(os.path.join(HERE, '_fix3.out.json'), 'w', encoding='utf-8').write(json.dumps({'ok': False, 'logs': logs}))
|
||||
return
|
||||
worst, pair = UPR.check(up_new, obs_s, obs_v, pads)
|
||||
lens = {n: sum(L(s) for s in up_new if s[6] == n) + sum(L(s) for s in pre['segs'] if s[6] == n) for n in UP}
|
||||
print(u'UP 重布:DP %.1f / DM %.1f mm(差 %.2f),对异网最小 %.3f(%s),对内 %.3f;禁区 y 33.0~%.2f'
|
||||
% (lens['UP_DP'], lens['UP_DM'], abs(lens['UP_DP'] - lens['UP_DM']), worst[0], worst[1], pair, FENCE_Y1))
|
||||
# ── 2. 板面换成新 UP;3. 拆 strap 网
|
||||
up_stub_s = [tuple(s[:7]) for s in pre['segs'] if s[6] in UP]
|
||||
up_stub_v = [tuple(v[:3]) for v in pre['vias'] if v[2] in UP]
|
||||
segs = [s for s in seg_all if s[6] not in UP and s[6] not in RIP] + up_stub_s + [tuple(s) for s in up_new]
|
||||
vias = [v for v in via_all if v[2] not in UP and v[2] not in RIP] + up_stub_v
|
||||
# ── 4. 按序补
|
||||
out, before = {}, {}
|
||||
for net, w in ORDER:
|
||||
groups = RN.components(net, pads, segs, vias)
|
||||
before[net] = len(groups)
|
||||
if len(groups) < 2:
|
||||
print(u'%-9s 已连通,跳过' % net)
|
||||
continue
|
||||
ps = RN.reps(groups)
|
||||
lg = []
|
||||
s, v = R.route_one(net, ps, w, pads, [x for x in segs if x[0] in (1, 2)], vias, [], lg)
|
||||
segs += [tuple(x) for x in s]
|
||||
vias += [tuple(x) for x in v]
|
||||
after = len(RN.components(net, pads, segs, vias))
|
||||
out[net] = {'segs': [list(x) for x in s], 'vias': [list(x) for x in v], 'before': len(groups), 'after': after}
|
||||
print(u'%-9s %d 块 → %d 块;新增 %d 段 %.1f mm / %d 孔(线宽 %.2f)%s'
|
||||
% (net, len(groups), after, len(s), sum(L(x) for x in s), len(v), w, (u';' + ';'.join(lg)) if lg else ''))
|
||||
logs += lg
|
||||
bad = [n for n, o in out.items() if o['after'] > 1]
|
||||
print(u'仍断开:%s' % (' '.join(bad) or u'无'))
|
||||
io.open(os.path.join(HERE, '_fix3.out.json'), 'w', encoding='utf-8').write(json.dumps(
|
||||
{'ok': True, 'up_new': [list(s) for s in up_new], 'rip': RIP, 'nets': out, 'before': before, 'bad': bad,
|
||||
'logs': logs, 'fence_y1': FENCE_Y1, 'up_worst': worst, 'up_pair': pair}, ensure_ascii=False))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
在新工单中引用
屏蔽一个用户