Cube-view: M_CPU north, 45° stub-straight-stub connector pattern

- M_CPU placed north (above) its router
- All connectors: 45° stub from router → straight → 45° stub to component
- Consistent 4-point polyline pattern for PE, M_CPU, SRAM, HBM, UCIe

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-05 00:34:48 -07:00
parent 72acc5c8bb
commit 5125d92c17
2 changed files with 130 additions and 120 deletions
+92 -82
View File
@@ -607,10 +607,14 @@ def _render_cube_view_svg(view: ViewGraph, spec: dict) -> str:
# Use left/right offset for multiple blocks on same router
offset_x = (bi - (len(blocks) - 1) / 2) * (blk_w + 4)
if kind in ("mcpu", "sram"):
# M_CPU/SRAM: place to the left of router (avoid mesh overlap)
bx = px - r_size - blk_w - 6
by = py - blk_h / 2 + bi * (blk_h + 2)
if kind == "mcpu":
# M_CPU: place above (north of) router
bx = px - blk_w / 2
by = py - r_size - blk_h - 8
elif kind == "sram":
# SRAM: place below (south of) router
bx = px - blk_w / 2
by = py + r_size + 8
else:
# PE: place above (top half) or below (bottom half)
bx = px + offset_x - blk_w / 2
@@ -632,50 +636,53 @@ def _render_cube_view_svg(view: ViewGraph, spec: dict) -> str:
f'text-anchor="middle" font-family="monospace" font-size="{font_sz}" '
f'font-weight="bold" fill="{style["text"]}">{_escape(label)}</text>'
)
# Connector line: router → component (diagonal out from router, then straight)
# Connector: router ─45°─ straight ─45°─ component
sc = style["stroke"]
if kind in ("mcpu", "sram"):
# Router → 45° diagonal → horizontal to block
x1 = bx + blk_w # block right edge
y1 = by + blk_h / 2
x2 = px - r_size # router left edge
y2 = py
dy = abs(y2 - y1)
# From router: diagonal 45° toward block, then horizontal
mid_x = x2 - dy # 45° means dx == dy
if mid_x < x1:
mid_x = x1
d = 6 # 45° stub length (px)
if kind == "mcpu":
# Router top → 45° NW stub → vertical → 45° into block bottom
rx2, ry2 = px, py - r_size
bxc, byc = bx + blk_w / 2, by + blk_h
parts.append(
f' <polyline points="{x2:.0f},{y2:.0f} {mid_x:.0f},{y1:.0f} {x1:.0f},{y1:.0f}" '
f' <polyline points="'
f'{rx2:.0f},{ry2:.0f} {rx2 - d:.0f},{ry2 - d:.0f} '
f'{rx2 - d:.0f},{byc + d:.0f} {bxc:.0f},{byc:.0f}" '
f'fill="none" stroke="{sc}" stroke-width="1" opacity="0.6"/>'
)
elif kind == "sram":
# Router bottom → 45° SW stub → vertical → 45° into block top
rx2, ry2 = px, py + r_size
bxc, byc = bx + blk_w / 2, by
parts.append(
f' <polyline points="'
f'{rx2:.0f},{ry2:.0f} {rx2 - d:.0f},{ry2 + d:.0f} '
f'{rx2 - d:.0f},{byc - d:.0f} {bxc:.0f},{byc:.0f}" '
f'fill="none" stroke="{sc}" stroke-width="1" opacity="0.6"/>'
)
else:
# PE: Router → 45° diagonal → vertical to block
# PE: vertical direction
bxc = bx + blk_w / 2 + offset_x
if is_top:
x1 = bx + blk_w / 2 + offset_x # block center
y1 = by + blk_h # block bottom
x2 = px # router center
y2 = py - r_size # router top
dx = abs(x2 - x1)
# From router: 45° diagonal, then vertical to block
mid_y = y2 - dx
if mid_y < y1:
mid_y = y1
rx2, ry2 = px, py - r_size # router top
byc = by + blk_h # block bottom
# 45° stub from router, vertical, 45° into block
sx = bxc - px # horizontal shift direction
sd = d if sx >= 0 else -d
parts.append(
f' <polyline points="{x2:.0f},{y2:.0f} {x1:.0f},{mid_y:.0f} {x1:.0f},{y1:.0f}" '
f' <polyline points="'
f'{rx2:.0f},{ry2:.0f} {rx2 + sd:.0f},{ry2 - d:.0f} '
f'{rx2 + sd:.0f},{byc + d:.0f} {bxc:.0f},{byc:.0f}" '
f'fill="none" stroke="{sc}" stroke-width="1" opacity="0.6"/>'
)
else:
x1 = bx + blk_w / 2 + offset_x
y1 = by # block top
x2 = px
y2 = py + r_size # router bottom
dx = abs(x2 - x1)
mid_y = y2 + dx
if mid_y > y1:
mid_y = y1
rx2, ry2 = px, py + r_size # router bottom
byc = by # block top
sx = bxc - px
sd = d if sx >= 0 else -d
parts.append(
f' <polyline points="{x2:.0f},{y2:.0f} {x1:.0f},{mid_y:.0f} {x1:.0f},{y1:.0f}" '
f' <polyline points="'
f'{rx2:.0f},{ry2:.0f} {rx2 + sd:.0f},{ry2 + d:.0f} '
f'{rx2 + sd:.0f},{byc - d:.0f} {bxc:.0f},{byc:.0f}" '
f'fill="none" stroke="{sc}" stroke-width="1" opacity="0.6"/>'
)
@@ -697,23 +704,26 @@ def _render_cube_view_svg(view: ViewGraph, spec: dict) -> str:
rpx, rpy = mm2px(rx, ry)
tgx, tgy = _pe_hbm_targets[pe_id]
r_edge_y = rpy + r_size if rpy < hbm_y else rpy - r_size
# From router: 45° diagonal toward HBM port, then vertical to port
dx = abs(tgx - rpx)
# 45° stub from router → vertical → 45° into HBM port
d = 8 # stub length
sx = tgx - rpx
sd = d if sx >= 0 else -d
if rpy < hbm_y:
# Top half: router bottom → 45° diagonal → vertical down to HBM top
mid_y = r_edge_y + dx
if mid_y > tgy:
mid_y = tgy
parts.append(
f' <polyline points="'
f'{rpx:.0f},{r_edge_y:.0f} {rpx + sd:.0f},{r_edge_y + d:.0f} '
f'{rpx + sd:.0f},{tgy - d:.0f} {tgx:.0f},{tgy:.0f}" '
f'fill="none" stroke="#10b981" stroke-width="1.5" opacity="0.6" '
f'stroke-dasharray="4,3"/>'
)
else:
# Bottom half: router top → 45° diagonal → vertical up to HBM bottom
mid_y = r_edge_y - dx
if mid_y < tgy:
mid_y = tgy
parts.append(
f' <polyline points="{rpx:.0f},{r_edge_y:.0f} {tgx:.0f},{mid_y:.0f} {tgx:.0f},{tgy:.0f}" '
f'fill="none" stroke="#10b981" stroke-width="1.5" opacity="0.6" '
f'stroke-dasharray="4,3"/>'
)
parts.append(
f' <polyline points="'
f'{rpx:.0f},{r_edge_y:.0f} {rpx + sd:.0f},{r_edge_y - d:.0f} '
f'{rpx + sd:.0f},{tgy + d:.0f} {tgx:.0f},{tgy:.0f}" '
f'fill="none" stroke="#10b981" stroke-width="1.5" opacity="0.6" '
f'stroke-dasharray="4,3"/>'
)
# BW annotation at midpoint
mx = (rpx + tgx) / 2 + 10
my = (r_edge_y + tgy) / 2
@@ -807,51 +817,51 @@ def _render_cube_view_svg(view: ViewGraph, spec: dict) -> str:
f'{conn}</text>'
)
# Connector line: router → UCIe port (diagonal from router, then straight)
# Connector: router ─45°stub─ straight ─45°stub─ UCIe port
rpx, rpy = mm2px(crx, cry)
d = 6
if direction == "N":
# Router top → 45° diagonal → vertical to UCIe port
x2, y2 = rpx, rpy - r_size # router top
x1, y1 = lx, cy_box + ch # port bottom
dx = abs(x1 - x2)
mid_y = y2 - dx
if mid_y < y1:
mid_y = y1
rx, ry = rpx, rpy - r_size
tx, ty = lx, cy_box + ch
sx = tx - rx
sd = d if sx >= 0 else -d
parts.append(
f' <polyline points="{x2:.0f},{y2:.0f} {x1:.0f},{mid_y:.0f} {x1:.0f},{y1:.0f}" '
f' <polyline points="'
f'{rx:.0f},{ry:.0f} {rx + sd:.0f},{ry - d:.0f} '
f'{rx + sd:.0f},{ty + d:.0f} {tx:.0f},{ty:.0f}" '
f'fill="none" stroke="{c_color}" stroke-width="1" opacity="0.5"/>'
)
elif direction == "S":
x2, y2 = rpx, rpy + r_size
x1, y1 = lx, cy_box
dx = abs(x1 - x2)
mid_y = y2 + dx
if mid_y > y1:
mid_y = y1
rx, ry = rpx, rpy + r_size
tx, ty = lx, cy_box
sx = tx - rx
sd = d if sx >= 0 else -d
parts.append(
f' <polyline points="{x2:.0f},{y2:.0f} {x1:.0f},{mid_y:.0f} {x1:.0f},{y1:.0f}" '
f' <polyline points="'
f'{rx:.0f},{ry:.0f} {rx + sd:.0f},{ry + d:.0f} '
f'{rx + sd:.0f},{ty - d:.0f} {tx:.0f},{ty:.0f}" '
f'fill="none" stroke="{c_color}" stroke-width="1" opacity="0.5"/>'
)
elif direction == "W":
x2, y2 = rpx - r_size, rpy
x1, y1 = cx + cw, cy_box + ch / 2
dy = abs(y1 - y2)
mid_x = x2 - dy
if mid_x < x1:
mid_x = x1
rx, ry = rpx - r_size, rpy
tx, ty = cx + cw, cy_box + ch / 2
sy = ty - ry
sd = d if sy >= 0 else -d
parts.append(
f' <polyline points="{x2:.0f},{y2:.0f} {mid_x:.0f},{y1:.0f} {x1:.0f},{y1:.0f}" '
f' <polyline points="'
f'{rx:.0f},{ry:.0f} {rx - d:.0f},{ry + sd:.0f} '
f'{tx + d:.0f},{ry + sd:.0f} {tx:.0f},{ty:.0f}" '
f'fill="none" stroke="{c_color}" stroke-width="1" opacity="0.5"/>'
)
elif direction == "E":
x2, y2 = rpx + r_size, rpy
x1, y1 = cx, cy_box + ch / 2
dy = abs(y1 - y2)
mid_x = x2 + dy
if mid_x > x1:
mid_x = x1
rx, ry = rpx + r_size, rpy
tx, ty = cx, cy_box + ch / 2
sy = ty - ry
sd = d if sy >= 0 else -d
parts.append(
f' <polyline points="{x2:.0f},{y2:.0f} {mid_x:.0f},{y1:.0f} {x1:.0f},{y1:.0f}" '
f' <polyline points="'
f'{rx:.0f},{ry:.0f} {rx + d:.0f},{ry + sd:.0f} '
f'{tx - d:.0f},{ry + sd:.0f} {tx:.0f},{ty:.0f}" '
f'fill="none" stroke="{c_color}" stroke-width="1" opacity="0.5"/>'
)