Update web viewer for router mesh topology (ADR-0019)

Remove all xbar/bridge rendering from cube detail view.
Replace 8 HBM slices with single HBM_CTRL block.
Add green dotted lines showing router-to-HBM connectivity.
Update legend, event animation, and PE view NOC destinations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-04 17:56:05 -07:00
parent 5917b3497c
commit 624161f52f
+56 -215
View File
@@ -26,8 +26,8 @@
--pe-stroke: #a855f7; --pe-stroke: #a855f7;
--io-fill: #3d2b1f; --io-fill: #3d2b1f;
--io-stroke: #f97316; --io-stroke: #f97316;
--xbar-fill: #1f2d3d; --router-fill: #1f2d3d;
--xbar-stroke: #06b6d4; --router-stroke: #06b6d4;
--link-color: #475569; --link-color: #475569;
--link-active: #3b82f6; --link-active: #3b82f6;
} }
@@ -405,8 +405,8 @@ body {
PE PE
</div> </div>
<div class="legend-item"> <div class="legend-item">
<div class="legend-swatch" style="background:var(--xbar-fill);border-color:var(--xbar-stroke)"></div> <div class="legend-swatch" style="background:var(--router-fill);border-color:var(--router-stroke)"></div>
XBAR / NOC Router Mesh
</div> </div>
</div> </div>
@@ -716,7 +716,7 @@ function drawCubeNode(svg, x, y, idx) {
g.appendChild(pt); g.appendChild(pt);
} }
// Center block: xbar + NOC // Center block: router mesh
g.appendChild(svgEl("rect", { g.appendChild(svgEl("rect", {
x: x + 30, y: y + 30, width: CUBE_W - 60, height: CUBE_H - 56, x: x + 30, y: y + 30, width: CUBE_W - 60, height: CUBE_H - 56,
rx: 3, fill: "#1f2d3d", stroke: "#06b6d466", "stroke-width": 0.8 rx: 3, fill: "#1f2d3d", stroke: "#06b6d466", "stroke-width": 0.8
@@ -728,7 +728,7 @@ function drawCubeNode(svg, x, y, idx) {
"font-size": "7", "font-size": "7",
fill: "#06b6d4aa" fill: "#06b6d4aa"
}); });
xt.textContent = "NOC+XBAR"; xt.textContent = "Router Mesh";
g.appendChild(xt); g.appendChild(xt);
// HBM indicators (top and bottom) // HBM indicators (top and bottom)
@@ -871,51 +871,6 @@ function drawCubeView(svg, cubeIdx) {
} }
} }
// ── PE router → XBAR_TOP paths (90-degree angled, matching reference) ──
// r0c0 → XBAR_TOP left: down then right
const xbarTopY = OY + 145; // reference: rect at y=145
const xbarBotY = OY + 355; // reference: rect at y=355
const xbarX = OX + 150; // reference: x=150
const xbarW = 400; // reference: width=400
svg.appendChild(svgEl("path", {
d: `M ${OX} ${OY+16} V ${xbarTopY+6} H ${xbarX}`,
fill: "none", stroke: "#f97316", "stroke-width": 1.5, "stroke-dasharray": "4,3"
}));
svg.appendChild(svgEl("path", {
d: `M ${OX+140} ${OY+16} V ${xbarTopY} H ${xbarX}`,
fill: "none", stroke: "#f97316", "stroke-width": 1.5, "stroke-dasharray": "4,3"
}));
svg.appendChild(svgEl("path", {
d: `M ${OX+560} ${OY+107} V ${xbarTopY} H ${xbarX+xbarW}`,
fill: "none", stroke: "#f97316", "stroke-width": 1.5, "stroke-dasharray": "4,3"
}));
svg.appendChild(svgEl("path", {
d: `M ${OX+700} ${OY+107} V ${xbarTopY+6} H ${xbarX+xbarW}`,
fill: "none", stroke: "#f97316", "stroke-width": 1.5, "stroke-dasharray": "4,3"
}));
// ── XBAR_TOP bar ──
svg.appendChild(svgEl("rect", {
x: xbarX, y: xbarTopY, width: xbarW, height: 22,
rx: 5, fill: "#f97316", stroke: "#ea580c", "stroke-width": 2
}));
const xtT = svgEl("text", {
x: xbarX + xbarW / 2, y: xbarTopY + 15, "text-anchor": "middle",
"font-family": "monospace", "font-size": "9", "font-weight": "bold", fill: "white"
});
xtT.textContent = "XBAR_TOP | xbar_v1 | 2.0ns";
svg.appendChild(xtT);
// ── XBAR_TOP → HBM0-3 arrows ──
const hbmArrowXs = [OX + 225, OX + 320, OX + 415, OX + 475];
for (const ax of hbmArrowXs) {
svg.appendChild(svgEl("line", {
x1: ax, y1: xbarTopY + 22, x2: ax, y2: OY + 198,
stroke: "#059669", "stroke-width": 1.5
}));
}
// ── HBM ZONE ── // ── HBM ZONE ──
const hbmZoneX = OX + 145, hbmZoneY = OY + 195, hbmZoneW = 410, hbmZoneH = 152; const hbmZoneX = OX + 145, hbmZoneY = OY + 195, hbmZoneW = 410, hbmZoneH = 152;
svg.appendChild(svgEl("rect", { svg.appendChild(svgEl("rect", {
@@ -926,181 +881,71 @@ function drawCubeView(svg, cubeIdx) {
x: hbmZoneX + hbmZoneW / 2, y: hbmZoneY + 16, "text-anchor": "middle", x: hbmZoneX + hbmZoneW / 2, y: hbmZoneY + 16, "text-anchor": "middle",
"font-family": "monospace", "font-size": "9", "font-weight": "bold", fill: "#047857" "font-family": "monospace", "font-size": "9", "font-weight": "bold", fill: "#047857"
}); });
hzmLabel.textContent = "HBM 9.0 x 5.0 mm | hbm_ctrl_v1 x 8"; hzmLabel.textContent = "HBM 9.0 x 5.0 mm | hbm_ctrl_v1";
svg.appendChild(hzmLabel); svg.appendChild(hzmLabel);
// HBM0-3 (top row) // Single HBM_CTRL block (centered in HBM zone)
const hbmSliceW = 85, hbmSliceH = 28; const hbmCtrlG = svgEl("g", { class: "node-group", "data-id": "hbm_ctrl" });
const hbmTopSlices = [ hbmCtrlG.appendChild(svgEl("rect", {
{ x: OX + 168, label: "HBM0" }, { x: OX + 260, label: "HBM1" }, x: hbmZoneX + 40, y: hbmZoneY + 28, width: hbmZoneW - 80, height: 40,
{ x: OX + 352, label: "HBM2" }, { x: OX + 444, label: "HBM3" } rx: 6, fill: "#047857", stroke: "#065f46", "stroke-width": 1.5
]; }));
for (const hs of hbmTopSlices) { const hbmCtrlT = svgEl("text", {
const g = svgEl("g", { class: "node-group", "data-id": hs.label.toLowerCase() }); x: hbmZoneX + hbmZoneW / 2, y: hbmZoneY + 53, "text-anchor": "middle",
g.appendChild(svgEl("rect", { "font-family": "monospace", "font-size": "10", "font-weight": "bold", fill: "white"
x: hs.x, y: hbmZoneY + 23, width: hbmSliceW, height: hbmSliceH, });
rx: 4, fill: "#047857", stroke: "#065f46", "stroke-width": 1.5 hbmCtrlT.textContent = "HBM_CTRL";
})); hbmCtrlG.appendChild(hbmCtrlT);
const t = svgEl("text", { svg.appendChild(hbmCtrlG);
x: hs.x + hbmSliceW / 2, y: hbmZoneY + 23 + 18, "text-anchor": "middle",
"font-family": "monospace", "font-size": "8", "font-weight": "bold", fill: "white"
});
t.textContent = hs.label;
g.appendChild(t);
svg.appendChild(g);
}
// Exclusion zone label // Exclusion zone label
const hexLabel = svgEl("text", { const hexLabel = svgEl("text", {
x: hbmZoneX + hbmZoneW / 2, y: hbmZoneY + 75, "text-anchor": "middle", x: hbmZoneX + hbmZoneW / 2, y: hbmZoneY + 85, "text-anchor": "middle",
"font-family": "monospace", "font-size": "7", fill: "#ef4444aa" "font-family": "monospace", "font-size": "7", fill: "#ef4444aa"
}); });
hexLabel.textContent = "Router exclusion: r2c2, r2c3, r3c2, r3c3"; hexLabel.textContent = "Router exclusion: r2c2, r2c3, r3c2, r3c3";
svg.appendChild(hexLabel); svg.appendChild(hexLabel);
// HBM4-7 (bottom row) // "All routers connect to HBM" annotation
const hbmBotSlices = [ const hbmAnnot = svgEl("text", {
{ x: OX + 168, label: "HBM4" }, { x: OX + 260, label: "HBM5" }, x: hbmZoneX + hbmZoneW / 2, y: hbmZoneY + 100, "text-anchor": "middle",
{ x: OX + 352, label: "HBM6" }, { x: OX + 444, label: "HBM7" } "font-family": "monospace", "font-size": "6", fill: "#059669aa"
});
hbmAnnot.textContent = "All routers → HBM_CTRL (mesh-connected)";
svg.appendChild(hbmAnnot);
// ── HBM connectivity indicators (thin green dotted lines from edge routers to HBM zone) ──
// Draw thin green dotted lines from routers adjacent to HBM zone down/up to HBM
const hbmConnRouters = [
{ r: 1, c: 2 }, { r: 1, c: 3 }, // top edge of HBM zone
{ r: 4, c: 2 }, { r: 4, c: 3 }, // bottom edge of HBM zone
{ r: 2, c: 1 }, { r: 3, c: 1 }, // left edge of HBM zone
{ r: 2, c: 4 }, { r: 3, c: 4 }, // right edge of HBM zone
]; ];
for (const hs of hbmBotSlices) { for (const hr of hbmConnRouters) {
const g = svgEl("g", { class: "node-group", "data-id": hs.label.toLowerCase() }); const rp = rXY(hr.r, hr.c);
g.appendChild(svgEl("rect", { // Draw line toward the HBM zone center
x: hs.x, y: hbmZoneY + hbmZoneH - hbmSliceH - 23 + 10, width: hbmSliceW, height: hbmSliceH, const hbmCenterX = hbmZoneX + hbmZoneW / 2;
rx: 4, fill: "#065f46", stroke: "#064e3b", "stroke-width": 1.5 const hbmCenterY = hbmZoneY + hbmZoneH / 2;
})); // Compute endpoint clipped to HBM zone edge
const t = svgEl("text", { let ex = hbmCenterX, ey = hbmCenterY;
x: hs.x + hbmSliceW / 2, y: hbmZoneY + hbmZoneH - hbmSliceH - 23 + 10 + 18, "text-anchor": "middle", if (hr.r <= 1) { ey = hbmZoneY; ex = rp.x; } // top routers → top of HBM zone
"font-family": "monospace", "font-size": "8", "font-weight": "bold", fill: "white" else if (hr.r >= 4) { ey = hbmZoneY + hbmZoneH; ex = rp.x; } // bottom routers → bottom of HBM zone
}); else if (hr.c <= 1) { ex = hbmZoneX; ey = rp.y; } // left routers → left of HBM zone
t.textContent = hs.label; else { ex = hbmZoneX + hbmZoneW; ey = rp.y; } // right routers → right of HBM zone
g.appendChild(t);
svg.appendChild(g);
}
// ── XBAR_BOT → HBM4-7 arrows (upward) ──
for (const ax of hbmArrowXs) {
svg.appendChild(svgEl("line", { svg.appendChild(svgEl("line", {
x1: ax, y1: xbarBotY, x2: ax, y2: OY + 315, x1: rp.x, y1: rp.y, x2: ex, y2: ey,
stroke: "#059669", "stroke-width": 1.5 stroke: "#05966988", "stroke-width": 1, "stroke-dasharray": "3,3"
})); }));
} }
// ── XBAR_BOT bar ──
svg.appendChild(svgEl("rect", {
x: xbarX, y: xbarBotY, width: xbarW, height: 22,
rx: 5, fill: "#f97316", stroke: "#ea580c", "stroke-width": 2
}));
const xbT = svgEl("text", {
x: xbarX + xbarW / 2, y: xbarBotY + 15, "text-anchor": "middle",
"font-family": "monospace", "font-size": "9", "font-weight": "bold", fill: "white"
});
xbT.textContent = "XBAR_BOT | xbar_v1 | 2.0ns";
svg.appendChild(xbT);
// ── PE router → XBAR_BOT paths (90-degree angled) ──
svg.appendChild(svgEl("path", {
d: `M ${OX} ${OY+409} V ${xbarBotY+16} H ${xbarX}`,
fill: "none", stroke: "#f97316", "stroke-width": 1.5, "stroke-dasharray": "4,3"
}));
svg.appendChild(svgEl("path", {
d: `M ${OX+140} ${OY+409} V ${xbarBotY+10} H ${xbarX}`,
fill: "none", stroke: "#f97316", "stroke-width": 1.5, "stroke-dasharray": "4,3"
}));
svg.appendChild(svgEl("path", {
d: `M ${OX+560} ${OY+508} V ${xbarBotY+10} H ${xbarX+xbarW}`,
fill: "none", stroke: "#f97316", "stroke-width": 1.5, "stroke-dasharray": "4,3"
}));
svg.appendChild(svgEl("path", {
d: `M ${OX+700} ${OY+508} V ${xbarBotY+16} H ${xbarX+xbarW}`,
fill: "none", stroke: "#f97316", "stroke-width": 1.5, "stroke-dasharray": "4,3"
}));
// ── BRIDGES (purple/violet, matching reference) ──
const brgLeftX = OX + 100, brgRightX = OX + 600;
// Left bridge vertical line
svg.appendChild(svgEl("line", {
x1: brgLeftX, y1: xbarTopY + 10, x2: brgLeftX, y2: xbarBotY + 12,
stroke: "#a78bfa", "stroke-width": 2.5, "stroke-dasharray": "8,4"
}));
// Left bridge horizontal stubs
svg.appendChild(svgEl("line", {
x1: brgLeftX, y1: xbarTopY + 6, x2: xbarX, y2: xbarTopY + 6,
stroke: "#a78bfa", "stroke-width": 2, "stroke-dasharray": "6,3"
}));
svg.appendChild(svgEl("line", {
x1: brgLeftX, y1: xbarBotY + 16, x2: xbarX, y2: xbarBotY + 16,
stroke: "#a78bfa", "stroke-width": 2, "stroke-dasharray": "6,3"
}));
// Left bridge label
svg.appendChild(svgEl("rect", {
x: brgLeftX - 28, y: OY + 248, width: 56, height: 30,
rx: 4, fill: "#1e1b4b", stroke: "#a78bfa", "stroke-width": 1.5
}));
let bt = svgEl("text", {
x: brgLeftX, y: OY + 259, "text-anchor": "middle",
"font-family": "monospace", "font-size": "6", "font-weight": "bold", fill: "#a78bfa"
});
bt.textContent = "XBAR BRG";
svg.appendChild(bt);
bt = svgEl("text", {
x: brgLeftX, y: OY + 272, "text-anchor": "middle",
"font-family": "monospace", "font-size": "7", "font-weight": "bold", fill: "#a78bfa"
});
bt.textContent = "LEFT";
svg.appendChild(bt);
bt = svgEl("text", {
x: brgLeftX - 36, y: OY + 263, "text-anchor": "end",
"font-family": "monospace", "font-size": "6", fill: "#a78bfa88"
});
bt.textContent = "3mm";
svg.appendChild(bt);
// Right bridge vertical line
svg.appendChild(svgEl("line", {
x1: brgRightX, y1: xbarTopY + 10, x2: brgRightX, y2: xbarBotY + 12,
stroke: "#a78bfa", "stroke-width": 2.5, "stroke-dasharray": "8,4"
}));
// Right bridge horizontal stubs
svg.appendChild(svgEl("line", {
x1: brgRightX, y1: xbarTopY + 6, x2: xbarX + xbarW, y2: xbarTopY + 6,
stroke: "#a78bfa", "stroke-width": 2, "stroke-dasharray": "6,3"
}));
svg.appendChild(svgEl("line", {
x1: brgRightX, y1: xbarBotY + 16, x2: xbarX + xbarW, y2: xbarBotY + 16,
stroke: "#a78bfa", "stroke-width": 2, "stroke-dasharray": "6,3"
}));
// Right bridge label
svg.appendChild(svgEl("rect", {
x: brgRightX - 28, y: OY + 248, width: 56, height: 30,
rx: 4, fill: "#1e1b4b", stroke: "#a78bfa", "stroke-width": 1.5
}));
bt = svgEl("text", {
x: brgRightX, y: OY + 259, "text-anchor": "middle",
"font-family": "monospace", "font-size": "6", "font-weight": "bold", fill: "#a78bfa"
});
bt.textContent = "XBAR BRG";
svg.appendChild(bt);
bt = svgEl("text", {
x: brgRightX, y: OY + 272, "text-anchor": "middle",
"font-family": "monospace", "font-size": "7", "font-weight": "bold", fill: "#a78bfa"
});
bt.textContent = "RIGHT";
svg.appendChild(bt);
bt = svgEl("text", {
x: brgRightX + 36, y: OY + 263,
"font-family": "monospace", "font-size": "6", fill: "#a78bfa88"
});
bt.textContent = "3mm";
svg.appendChild(bt);
// ── M_CPU (r2c0) and SRAM (r3c0) labels ── // ── M_CPU (r2c0) and SRAM (r3c0) labels ──
const mcpuP = rXY(2, 0); const mcpuP = rXY(2, 0);
svg.appendChild(svgEl("rect", { svg.appendChild(svgEl("rect", {
x: mcpuP.x - 42, y: mcpuP.y + 18, width: 84, height: 18, x: mcpuP.x - 42, y: mcpuP.y + 18, width: 84, height: 18,
rx: 4, fill: "#f59e0b", stroke: "#d97706", "stroke-width": 1.5 rx: 4, fill: "#f59e0b", stroke: "#d97706", "stroke-width": 1.5
})); }));
bt = svgEl("text", { let bt = svgEl("text", {
x: mcpuP.x, y: mcpuP.y + 31, "text-anchor": "middle", x: mcpuP.x, y: mcpuP.y + 31, "text-anchor": "middle",
"font-family": "monospace", "font-size": "8", "font-weight": "bold", fill: "white" "font-family": "monospace", "font-size": "8", "font-weight": "bold", fill: "white"
}); });
@@ -1358,8 +1203,7 @@ function drawCubeView(svg, cubeIdx) {
{ color: "#e2e8f0", label: "Relay", textColor: "#475569" }, { color: "#e2e8f0", label: "Relay", textColor: "#475569" },
{ color: "#8b5cf6", label: "UCIe Router" }, { color: "#8b5cf6", label: "UCIe Router" },
{ color: "#f59e0b", label: "M_CPU/SRAM" }, { color: "#f59e0b", label: "M_CPU/SRAM" },
{ color: "#a78bfa", label: "Bridge", type: "line" }, { color: "#059669", label: "HBM Link", type: "line" },
{ color: "#f97316", label: "XBAR", type: "rect" },
{ color: "#047857", label: "HBM Ctrl", type: "rect" }, { color: "#047857", label: "HBM Ctrl", type: "rect" },
{ color: "#ef4444", label: "PE (~5mm2)", type: "rect" }, { color: "#ef4444", label: "PE (~5mm2)", type: "rect" },
{ color: "#8b5cf6", label: "UCIe Port", type: "rect", rectFill: "#1e1b4b" }, { color: "#8b5cf6", label: "UCIe Port", type: "rect", rectFill: "#1e1b4b" },
@@ -1394,7 +1238,7 @@ function drawCubeView(svg, cubeIdx) {
const dpT = svgEl("text", { const dpT = svgEl("text", {
x: 60, y: legY + 24, "font-family": "monospace", "font-size": "7", fill: "#64748b" x: 60, y: legY + 24, "font-family": "monospace", "font-size": "7", fill: "#64748b"
}); });
dpT.textContent = "Data: PE_DMA→NOC→XBAR→HBM | Cross-half: XBAR_TOP→Bridge(3mm)→XBAR_BOT→HBM4-7"; dpT.textContent = "Data: PE_DMA → Router Mesh → HBM_CTRL | All traffic routed through 6x6 mesh";
svg.appendChild(dpT); svg.appendChild(dpT);
} }
@@ -1454,7 +1298,7 @@ function drawPeView(svg, cubeIdx, peIdx) {
// NOC destinations (inside NOC column) // NOC destinations (inside NOC column)
const nocDests = [ const nocDests = [
{ label: "XBAR", sub: "→ HBM", y: nocTop + 50, fill: "#f97316", bg: "#3d2b1f" }, { label: "HBM", sub: "ctrl", y: nocTop + 50, fill: "#059669", bg: "#052e16" },
{ label: "SRAM", sub: "128x4", y: nocTop + 86, fill: "#f59e0b", bg: "#3d2b1f" }, { label: "SRAM", sub: "128x4", y: nocTop + 86, fill: "#f59e0b", bg: "#3d2b1f" },
{ label: "UCIe", sub: "inter", y: nocTop + 122, fill: "#8b5cf6", bg: "#1e1b4b" }, { label: "UCIe", sub: "inter", y: nocTop + 122, fill: "#8b5cf6", bg: "#1e1b4b" },
{ label: "M_CPU", sub: "cmd", y: nocTop + 158, fill: "#f59e0b", bg: "#3d2b1f" }, { label: "M_CPU", sub: "cmd", y: nocTop + 158, fill: "#f59e0b", bg: "#3d2b1f" },
@@ -1967,7 +1811,7 @@ function applyHotPaths(svg, t) {
} }
} else if (currentView === "cube") { } else if (currentView === "cube") {
// ── CUBE VIEW: highlight router mesh links + XBAR paths ── // ── CUBE VIEW: highlight router mesh links ──
const linkTraffic = {}; const linkTraffic = {};
for (const hop of activeHops) { for (const hop of activeHops) {
const linkId = hopToCubeLink(hop); const linkId = hopToCubeLink(hop);
@@ -1984,16 +1828,13 @@ function applyHotPaths(svg, t) {
inflight++; inflight++;
} }
} }
// Highlight XBAR/HBM components referenced in events // Highlight HBM component referenced in events
const activeProcesses = allEvents.filter(e => const activeProcesses = allEvents.filter(e =>
e.type === "process" && e.t_ns <= t && e.t_ns >= t - 30 e.type === "process" && e.t_ns <= t && e.t_ns >= t - 30
); );
for (const proc of activeProcesses) { for (const proc of activeProcesses) {
const comp = proc.component || ""; const comp = proc.component || "";
if (comp.includes("xbar_top")) highlightComponent(svg, "xbar_top"); if (comp.includes("hbm_ctrl")) highlightComponent(svg, "hbm_ctrl");
if (comp.includes("xbar_bot")) highlightComponent(svg, "xbar_bot");
const hbmMatch = comp.match(/hbm_ctrl\.slice(\d+)/);
if (hbmMatch) highlightComponent(svg, `hbm${hbmMatch[1]}`);
} }
} else if (currentView === "pe") { } else if (currentView === "pe") {