Show individual routers in cube_view SVG, fix row Y overlap

- cube_view now renders all 32 router nodes from cube_mesh.yaml
  instead of collapsed "router_mesh" placeholder
- Fix mesh_gen row Y position overlap (r1/r2 and r3/r4 had same Y)
  by adding hbm_gap spacing between PE rows and HBM zone
- Add noc_router to visualizer KIND_SIZE for proper sizing
- Update cube view tests for individual router nodes

339 passed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-04 18:22:38 -07:00
parent d2c92b8a18
commit 91085733ba
5 changed files with 395 additions and 183 deletions
+106 -76
View File
@@ -921,21 +921,26 @@ def _build_cube_view(spec: dict) -> ViewGraph:
label=name.upper().replace("_", " "),
)
# Router mesh representative node (collapsed for view)
router_spec = cube["components"]["noc_router"]
cx = cube_w / 2
cy = cube_h / 2
nodes["router_mesh"] = Node(
id="router_mesh", kind=router_spec["kind"], impl=router_spec["impl"],
attrs=router_spec["attrs"], pos_mm=(cx + 2.0, cy),
label="ROUTER MESH",
)
# Load mesh data early (needed for router nodes + PE distances)
mesh_data = spec.get("_mesh", {})
# PEs as opaque blocks (no per-PE xbar nodes)
# Router nodes from cube_mesh.yaml (explicit in view)
router_spec = cube["components"]["noc_router"]
routers = mesh_data.get("routers", {})
for rkey, rval in routers.items():
if rval is None:
continue
rx, ry = rval["pos_mm"]
nodes[rkey] = Node(
id=rkey, kind=router_spec["kind"], impl=router_spec["impl"],
attrs=router_spec["attrs"], pos_mm=(rx, ry),
label=rkey.upper(),
)
# PEs as opaque blocks
corners = cube["pe_layout"]["corners"]
pe_per_corner = cube["pe_layout"]["pe_per_corner"]
corner_pos = _corner_pe_positions(cube_w, cube_h)
mesh_data = spec.get("_mesh", {})
pe_noc_distances = _compute_pe_noc_distances(
mesh_data, corner_pos, corners, pe_per_corner,
) if mesh_data else {}
@@ -950,76 +955,101 @@ def _build_cube_view(spec: dict) -> ViewGraph:
attrs={"corner": corner}, pos_mm=(px, py),
label=f"PE{pe_idx}",
)
# PE ↔ router_mesh (view representation)
pe_to_router_bw = clinks.get("pe_to_router_bw_gbs", 256.0)
view_edges.append(Edge(
src=pid, dst="router_mesh",
distance_mm=pe_noc_distances.get(pe_idx, 0.0),
bw_gbs=pe_to_router_bw,
kind="pe_to_router",
))
view_edges.append(Edge(
src="router_mesh", dst=pid,
distance_mm=clinks.get("noc_to_pe_cpu_mm", 0.0),
kind="command",
))
pe_idx += 1
# router_mesh ↔ hbm_ctrl
# View edges based on cube_mesh.yaml attach (mirrors _instantiate_cube logic)
pe_to_router_bw = clinks.get("pe_to_router_bw_gbs", 256.0)
hbm_to_router_bw = clinks.get("hbm_to_router_bw_gbs", 256.0)
view_edges.append(Edge(
src="router_mesh", dst="hbm_ctrl",
distance_mm=0.0, bw_gbs=hbm_to_router_bw,
kind="router_to_hbm",
))
view_edges.append(Edge(
src="hbm_ctrl", dst="router_mesh",
distance_mm=0.0, bw_gbs=hbm_to_router_bw,
kind="hbm_to_router",
))
# router_mesh ↔ m_cpu
view_edges.append(Edge(
src="m_cpu", dst="router_mesh",
distance_mm=clinks.get("m_cpu_to_router_mm", 0.0),
kind="command",
))
view_edges.append(Edge(
src="router_mesh", dst="m_cpu",
distance_mm=clinks.get("m_cpu_to_router_mm", 0.0),
kind="command",
))
# router_mesh ↔ sram
sram_bw = clinks.get("sram_to_router_bw_gbs", 128.0)
view_edges.append(Edge(
src="router_mesh", dst="sram",
distance_mm=0.0, bw_gbs=sram_bw,
kind="router_to_sram",
))
ucie_conn_bw_v = ucie_cfg.get("per_connection_bw_gbs", 128.0)
for port in ucie_cfg["ports"]:
for ci in range(ucie_n_conn):
conn_id = f"ucie-{port}.conn{ci}"
view_edges.append(Edge(
src="router_mesh", dst=conn_id,
distance_mm=0.0, bw_gbs=ucie_conn_bw_v,
kind="router_to_ucie_conn",
))
view_edges.append(Edge(
src=conn_id, dst=f"ucie-{port}",
distance_mm=0.0, kind="ucie_internal",
))
view_edges.append(Edge(
src=f"ucie-{port}", dst=conn_id,
distance_mm=0.0, kind="ucie_internal",
))
view_edges.append(Edge(
src=conn_id, dst="router_mesh",
distance_mm=0.0, bw_gbs=ucie_conn_bw_v,
kind="ucie_conn_to_router",
))
n_rows = mesh_data.get("mesh", {}).get("rows", 6)
n_cols = mesh_data.get("mesh", {}).get("cols", 6)
# Router ↔ router mesh edges
for r in range(n_rows):
for c in range(n_cols):
rkey = f"r{r}c{c}"
if routers.get(rkey) is None:
continue
src_pos = routers[rkey]["pos_mm"]
# Horizontal neighbor
for nc in range(c + 1, n_cols):
nkey = f"r{r}c{nc}"
if routers.get(nkey) is None:
continue
dist = abs(routers[nkey]["pos_mm"][0] - src_pos[0])
view_edges.append(Edge(
src=rkey, dst=nkey, distance_mm=round(dist, 2),
kind="router_mesh",
))
break
# Vertical neighbor
for nr in range(r + 1, n_rows):
nkey = f"r{nr}c{c}"
if routers.get(nkey) is None:
continue
dist = abs(routers[nkey]["pos_mm"][1] - src_pos[1])
view_edges.append(Edge(
src=rkey, dst=nkey, distance_mm=round(dist, 2),
kind="router_mesh",
))
break
# Component ↔ router edges from attach lists
for rkey, rval in routers.items():
if rval is None:
continue
for item in rval.get("attach", []):
if item.endswith(".dma"):
pe_prefix = item.rsplit(".", 1)[0]
pid = pe_prefix.replace("pe", "pe") # "pe0" → "pe0"
if pid in nodes:
view_edges.append(Edge(
src=pid, dst=rkey, distance_mm=0.0,
bw_gbs=pe_to_router_bw, kind="pe_to_router",
))
view_edges.append(Edge(
src=rkey, dst=pid, distance_mm=0.0,
kind="command",
))
elif item.endswith(".hbm"):
view_edges.append(Edge(
src=rkey, dst="hbm_ctrl", distance_mm=0.0,
bw_gbs=hbm_to_router_bw, kind="router_to_hbm",
))
elif item == "m_cpu":
view_edges.append(Edge(
src="m_cpu", dst=rkey, distance_mm=0.0, kind="command",
))
view_edges.append(Edge(
src=rkey, dst="m_cpu", distance_mm=0.0, kind="command",
))
elif item == "sram":
view_edges.append(Edge(
src="sram", dst=rkey, distance_mm=0.0,
bw_gbs=sram_bw, kind="router_to_sram",
))
elif item.startswith("ucie_"):
parts = item.split(".")
direction = parts[0].replace("ucie_", "").upper()
conn_num = parts[1].replace("c", "")
conn_id = f"ucie-{direction}.conn{conn_num}"
view_edges.append(Edge(
src=rkey, dst=conn_id, distance_mm=0.0,
bw_gbs=ucie_conn_bw_v, kind="router_to_ucie_conn",
))
view_edges.append(Edge(
src=conn_id, dst=rkey, distance_mm=0.0,
bw_gbs=ucie_conn_bw_v, kind="ucie_conn_to_router",
))
view_edges.append(Edge(
src=conn_id, dst=f"ucie-{direction}",
distance_mm=0.0, kind="ucie_internal",
))
view_edges.append(Edge(
src=f"ucie-{direction}", dst=conn_id,
distance_mm=0.0, kind="ucie_internal",
))
return ViewGraph(
name="cube", nodes=nodes, edges=view_edges,