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:
@@ -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,
|
||||
|
||||
@@ -111,6 +111,7 @@ def _compute_row_positions(
|
||||
|
||||
# Top half: evenly spaced from top PE y to just above HBM zone
|
||||
top_pe_y = 1.5
|
||||
hbm_gap = 1.5 # minimum gap between PE rows and HBM rows
|
||||
hbm_top_y = cube_h / 2 - 1.5 # ~5.5 for h=14
|
||||
hbm_bot_y = cube_h / 2 + 1.5 # ~8.5 for h=14
|
||||
bot_pe_y = cube_h - 1.5
|
||||
@@ -119,21 +120,24 @@ def _compute_row_positions(
|
||||
if rows_per_half == 1:
|
||||
top_rows = [top_pe_y]
|
||||
else:
|
||||
step = (hbm_top_y - top_pe_y) / (rows_per_half - 1) if rows_per_half > 1 else 0
|
||||
# End before HBM zone with gap
|
||||
top_end = hbm_top_y - hbm_gap
|
||||
step = (top_end - top_pe_y) / (rows_per_half - 1) if rows_per_half > 1 else 0
|
||||
for i in range(rows_per_half):
|
||||
top_rows.append(round(top_pe_y + i * step, 1))
|
||||
|
||||
# HBM rows
|
||||
hbm_rows = [round(hbm_top_y, 1), round(hbm_bot_y, 1)]
|
||||
|
||||
# Bottom half: mirror of top
|
||||
# Bottom half: mirror of top, start after HBM zone with gap
|
||||
bot_rows: list[float] = []
|
||||
if rows_per_half == 1:
|
||||
bot_rows = [bot_pe_y]
|
||||
else:
|
||||
step = (bot_pe_y - hbm_bot_y) / (rows_per_half - 1) if rows_per_half > 1 else 0
|
||||
bot_start = hbm_bot_y + hbm_gap
|
||||
step = (bot_pe_y - bot_start) / (rows_per_half - 1) if rows_per_half > 1 else 0
|
||||
for i in range(rows_per_half):
|
||||
bot_rows.append(round(hbm_bot_y + i * step, 1))
|
||||
bot_rows.append(round(bot_start + i * step, 1))
|
||||
|
||||
return top_rows + hbm_rows + bot_rows, rows_per_half
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ _KIND_SIZE: dict[str, tuple[float, float]] = {
|
||||
"cube": (6.0, 4.0),
|
||||
"iochiplet": (4.0, 1.5),
|
||||
"switch": (5.0, 1.5),
|
||||
"noc_router": (1.2, 0.8),
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user