DDR · Module 26
2.5D Packaging for HBM
A bump pitch turns an area into a count, and the face-versus-edge advantage has the closed form L/4p. The surprise is that a full 1024-bit bump field uses about 2% of a die's face.
Chapter 26.1 §1 established that connections per unit of capability fall as 4/L, and that the only way out is to stop using the perimeter and start using the face. It then assumed, without examining it, that a surface can be covered with connections at whatever density is required.
It cannot. There is a pitch below which connections cannot be placed and assembled, and that pitch — not the area — is what converts a surface into a count.
This chapter does that conversion. The result has a closed form, §4 derives it, and §5 reports the part that is genuinely surprising: a bump field carrying a full 1024-bit interface is a couple of millimetres square. The connection count is not the binding constraint, which raises the question of what is.
1. What the Interposer Provides
Chapter 4.8 §1 describes the arrangement: the stack and the processor sit side by side on a silicon interposer, rather than the memory routing to a socket across a board. It characterises the change as “a board trace is centimetres long with connector discontinuities; an interposer trace is short and on silicon, at a wiring pitch a printed circuit board cannot approach.”
That sentence contains two distinct properties, and they do different work:
| Property | What it buys |
|---|---|
| The trace is short | lower energy per bit, better signal quality |
| The wiring is dense | more connections can physically exist |
Both are real and only one of them is the enabling property. §2 is about which.
2. Density Is the Enabling Property
Shortness is valuable and it is not what makes HBM possible.
Consider the counterfactual. Suppose an interposer gave short traces at a conventional board's wiring density. Every signal would be electrically better — and 26.1 §1's wall would be exactly where it was, because the number of connections that can exist is set by pitch and area, not by trace length. A thousand-bit interface would still have nowhere to go.
Now the other counterfactual. Suppose the wiring were dense but the traces long. The connections would exist, each would be electrically worse, and the interface would be possible but expensive — which is a design problem rather than an impossibility.
So density is necessary and shortness is an improvement. That asymmetry matters because it tells you which property to protect when trading one against the other, and it is why the rest of this chapter is about pitch rather than about length.
3. A Pitch Turns an Area Into a Count
Here is the conversion 26.1 §1 assumed and did not perform.
The model, stated — and it has two forms that differ. Connections sit on a square grid of pitch p over a die of side L. The continuous form divides the areas:
continuous : A / p² = L² / p²But a fraction of a connection cannot be placed. The integer form counts whole positions per side and squares:
integer : floor(L/p)²The integer form is the physical one, and it is what §13's block computes. The two agree only when the pitch divides the side exactly.
DERIVED under the integer form, with ILLUSTRATIVE pitches and die sizes. Every value recomputed:
Die side L | Positions per side at 55 / 45 / 25 µm | Pitch 55 µm | Pitch 45 µm | Pitch 25 µm |
|---|---|---|---|---|
| 5 mm | 90 / 111 / 200 | 8,100 | 12,321 | 40,000 |
| 10 mm | 181 / 222 / 400 | 32,761 | 49,284 | 160,000 |
| 20 mm | 363 / 444 / 800 | 131,769 | 197,136 | 640,000 |
The 25 µm column is the only one where the two forms agree, because 25 divides 5,000, 10,000 and 20,000 exactly. Everywhere else the continuous form overstates the count — by 2.0% at 55 µm on a 5 mm die, and by less as the pitch gets finer relative to the die.
Two things follow from the exponents alone, independently of which pitch is real.
Halving the pitch quadruples the count. The count is quadratic in pitch, so pitch improvement is the strongest lever available — far stronger than area. The 25 µm column is 4.86× to 4.94× the 55 µm column across the three die sizes, against a continuous prediction of (55/25)² = 4.84 — the integer form runs slightly above it because flooring penalises the coarser pitch more.
And area helps only linearly. Quadrupling the area quadruples the count, which is the same factor a halved pitch achieves without growing the die. So for a given connection requirement, pitch is the variable to push and size is the variable to avoid pushing — which is the opposite of the intuition 26.1 §1 had to dismantle for the perimeter case.
4. Face Against Edge Has a Closed Form
Now compare the two surfaces directly, at the same pitch, so the comparison isolates geometry from manufacturing capability.
The model, stated. Take §3's continuous form for both surfaces. The face carries a square grid, L² / p²; the edge carries a single row around the perimeter, 4L / p. The ratio collapses:
face L² / p² L
──── = ───────── = ────
edge 4L / p 4pThe face-versus-edge advantage is L / 4p. A closed form, with the pitch cancelling from quadratic to linear.
DERIVED, with the integer-form ratio beside the closed form so the difference is visible:
| Die side | 55 µm: integer / L/4p | 45 µm: integer / L/4p | 25 µm: integer / L/4p |
|---|---|---|---|
| 5 mm | 22.3× / 22.7 | 27.8× / 27.8 | 50.0× / 50.0 |
| 10 mm | 45.1× / 45.5 | 55.5× / 55.6 | 100.0× / 100.0 |
| 20 mm | 90.6× / 90.9 | 110.9× / 111.1 | 200.0× / 200.0 |
The closed form is the continuous limit and the integer ratio sits just below it, agreeing exactly at 25 µm where the division is clean. At L = 10 mm and p = 45 µm the closed form gives 10000 / 180 = 55.6, and the integer counts from §3 give 49,284 / 888 = 55.5.
Why the integer form is slightly worse: flooring discards a partial row and a partial column on the face, which costs the count quadratically, while the edge loses only a partial row. So the discrepancy is largest where the pitch divides the side worst, and it vanishes when the division is exact.
Three readings, and the third is the one worth carrying.
The advantage grows with die size. L / 4p is linear in L, so a bigger die gains more from face connection — the exact inverse of 26.1 §1's finding that a bigger die suffers more from edge connection. The two results are the same fact stated from either side.
The advantage grows as pitch shrinks. Halving p doubles the ratio, because the face gains quadratically and the edge only linearly.
And the advantage is large at every plausible value. The smallest cell in the table is 22.7× and the largest 200×. There is no pitch or die size in this range at which edge connection is competitive, which is why the change of surface was not a marginal optimisation but a reorganisation of the whole package.
5. The Bump Field Is Smaller Than Expected
Turn the arithmetic around. Instead of asking how many connections an area provides, ask how much area a known requirement needs.
Chapter 4.8 §2 gives the requirement: 1024 signal bits. DERIVED at ILLUSTRATIVE pitches, signals only:
| Pitch | Area for 1024 bumps | As a square |
|---|---|---|
| 55 µm | 3.098 mm² | 1.76 mm |
| 45 µm | 2.074 mm² | 1.44 mm |
| 25 µm | 0.640 mm² | 0.80 mm |
A full 1024-bit interface's bump field is under two millimetres square at every pitch in the table.
That is the chapter's surprise, and it corrects a reasonable expectation. A thousand connections sounds like a lot and occupies almost no area. The comparison is with §3's totals: a 10 mm die's face at 45 µm offers 49,284 positions, and the interface needs 1,024 of them — 2.08%.
6. Not Every Bump Carries a Signal
§5's figures count signal bumps only, and no real interface is all signal. Power and ground need connections too, and they need many.
The model, stated. Express the overhead as a ratio of signal bumps to power-and-ground bumps. DERIVED at ILLUSTRATIVE ratios and pitches:
| Signal : power/ground | Total bumps | At 55 µm | At 45 µm | At 25 µm |
|---|---|---|---|---|
| all signal | 1,024 | 1.76 mm | 1.44 mm | 0.80 mm |
| 1 : 1 | 2,048 | 2.49 mm | 2.04 mm | 1.13 mm |
| 1 : 2 | 3,072 | 3.05 mm | 2.49 mm | 1.39 mm |
Even at two power-and-ground bumps per signal, the field is about 2.5 mm square at 45 µm. Tripling the bump count raises the side length by only √3 ≈ 1.73, because area grows as the square of the side — so overhead is cheap in linear dimension even when it is expensive in count.
Two consequences for §13's budget block.
The signal count alone cannot size a bump field. A block that accepted a signal count and a pitch and reported an area would be understating it by whatever the power overhead is — so the ratio is a required input rather than an optional one.
And the overhead is not a fixed property of the interface. It depends on current, which depends on activity, which is outside this chapter entirely. So §13 takes the ratio as a parameter and refuses to guess it, the same discipline 25.3 §12 applied to a regulator efficiency it could not obtain.
7. The Stack Above the Interposer
Chapter 4.8 §1 describes the stack in one sentence: several dies connected vertically, “with a logic die at the base of the stack handling the external interface”, in heights of 2, 4, 8 and 12 dies.
So the stack has two kinds of die and they are not interchangeable.
| Die | Role | How many |
|---|---|---|
| Core die | the DRAM array itself | 2, 4, 8 or 12 |
| Base die | the external interface | one, at the bottom |
The base die is the only one the interposer talks to. Every core die's traffic reaches the outside world through it, which makes it a shared resource for the whole stack and the natural place for anything the stack does collectively.
§9 is about what that role includes. First, what the height implies.
8. What the Capacity Figure Implies About a Core Die
Chapter 4.8 §2 publishes up to 24 GB of capacity, from stacks up to 12 dies high. Those two figures together determine a third that neither states.
CURRICULUM-DERIVED, recomputed:
24 GB / 12 core dies = 2 GB per die = 16 Gb per die
check : 16 Gb x 12 / 8 bits per byte = 24 GB exactSo 4.8's published pair implies a 16 Gb core die, exactly. Not approximately — the division is clean, and the check multiplies back to the stated capacity with no remainder.
That is a genuine inference from two verified figures and it is worth making because it fixes the scale of the thing being stacked. A core die is a DRAM die of a density this curriculum has met repeatedly, which means stacking is not a technique for building exotic dies — it is a technique for combining ordinary ones.
And the capacity scales linearly in height while §4's connection advantage scales in die size, which are independent variables. DERIVED under the 16 Gb-per-die inference:
| Stack height | Capacity |
|---|---|
| 2 | 4 GB |
| 4 | 8 GB |
| 8 | 16 GB |
| 12 | 24 GB |
Bandwidth does not appear in that table, and its absence is the point. The interface is 1024 bits wide regardless of how many dies sit behind it, so height buys capacity and not bandwidth — a separation 26.4 builds on directly.
9. The Base Die's Job
Chapter 4.8 calls it “a logic die at the base of the stack handling the external interface” and defers the detail. Its scope callout assigns “the stack's logic layer” to this module.
What follows from §7's structure alone, without needing a source:
It is the only die with an external interface. So it holds whatever converts between the stack's internal arrangement and the 1024-bit interface the interposer carries.
It is shared by every core die. Anything the stack does as a unit — responding to the host, distributing commands to the right core die, presenting a single identity — has one natural home, and this is it.
And it is at the bottom, which is where the interposer is. That is not an arbitrary placement: a base die in the middle would need its external connections routed vertically past the dies below it, spending exactly the vertical connections the stack exists to conserve.
10. What “2.5D” Means, and What It Does Not
The name is worth unpacking because it encodes exactly the partition §2's callout describes.
| Arrangement | Vertical connection | |
|---|---|---|
| 2D | dies side by side on a substrate | none — all routing is planar |
| 2.5D | dies side by side on an interposer | within the stack; not between stack and processor |
| 3D | dies stacked on each other | throughout, including processor to memory |
The distinguishing feature of 2.5D is that the memory and the processor are not stacked on each other. They are neighbours on a shared dense substrate. The stacking happens within the memory, and the processor-to-memory connection is lateral.
Two reasons that matters, and the second is the one usually missed.
The processor keeps its own thermal path. Chapter 4.8 §3 establishes that “a die in the middle of a stack is surrounded by other dies; its thermal path to anywhere useful runs through them” and that this is worst for DRAM because retention falls with temperature. Putting the processor — the hottest component — on top of or under the memory would combine the worst thermal arrangement with the most thermally sensitive part. Lateral placement keeps them thermally separate.
And the two dies can be manufactured and tested independently. They are different processes with different yields, brought together at assembly. Stacking them would couple their yields, which 4.8 §3's first cost already identifies as HBM's characteristic risk — 2.5D limits that coupling to the assembly step rather than extending it into the dies themselves.
So 2.5D is not a halfway house on the road to 3D. It is a specific choice that takes the density benefit of a silicon substrate while declining the thermal and yield coupling of true stacking between logic and memory.
11. The Assembly as Layers
Two things the layering makes visible.
Only one layer is stacked, and it is not the processor. The core dies stack; the processor is not in this picture at all, because §10 establishes it sits beside the interposer's stack rather than above or below it. A reader who expects the processor at the top or bottom of an HBM stack diagram has the 3D arrangement in mind, and that difference is what the name encodes.
And the density requirement drops as you descend. The microbump and interposer layers need the fine pitch §3 quantifies; the substrate below does not, because §2's callout establishes that only the wide interface needs density. The interposer exists to serve exactly two layers, and everything below it is conventional.
12. The Connection Budget as a Structure
Bump pitch is the only input that feeds three different computations — the face count, the edge count and the required area. That is why §3 calls it the strongest lever: it appears quadratically in two of the three and linearly in the third, so an improvement in pitch moves every quantity in the budget at once.
And Does it fit? has two inputs that come from opposite directions — what is needed and what is available. §5's finding is that these differ by roughly fifty times, which is why the answer is not interesting and the reason it is not interesting is.
13. The Connection Budget
// ---------------------------------------------------------------------
// bump_connection_budget -- converts an area and a pitch into a
// connection count, and checks a signal requirement against it.
//
// CLASSIFICATION: educational, synthesisable. COUNTING ONLY.
//
// WHAT IT DOES NOT MODEL -- and this list is the most important part
// of the block:
// - capacitance, resistance, inductance. A pitch has electrical
// consequences and NONE of them is computed here.
// - thermal resistance, temperature, yield, assembly tolerance,
// mechanical stress. 4.8 §3 owns the yield ARGUMENT; no block
// may compute a yield.
// - trace length or its energy consequence. §2: shortness is a
// real benefit and it is not what this block is about.
// A PITCH ENTERS AS AN INTEGER AND IS USED ONLY TO COUNT. Converting
// it to an electrical result would be this module's fake-eye failure
// (22.3), and the discipline is absolute.
//
// UNITS: pitch in micrometres, side lengths in micrometres, areas in
// square micrometres. Integers throughout -- no fixed point, no
// division where a comparison will do.
// ---------------------------------------------------------------------
module bump_connection_budget #(
// ILLUSTRATIVE defaults. No pitch or die size in this module
// was verified from any source.
parameter int DIE_SIDE_UM = 10000, // 10 mm, ILLUSTRATIVE
parameter int PITCH_UM = 45, // ILLUSTRATIVE
parameter int SIGNAL_BUMPS = 1024, // CURRICULUM-DERIVED (4.8 §2)
// §6: power/ground bumps per signal bump, as a numerator over a
// denominator so a caller can express 1:2 or 3:4 without a real.
parameter int PG_NUM = 2,
parameter int PG_DEN = 1,
parameter int CNT_W = 32
) (
input logic clk,
input logic rst_n,
// ── Query a hypothetical pitch at runtime, so a design can budget
// more than one option without re-elaborating.
input logic q_valid,
input logic [15:0] q_pitch_um,
// ── Counts at the ELABORATED pitch.
output logic [CNT_W-1:0] face_positions,
output logic [CNT_W-1:0] edge_positions,
output logic [CNT_W-1:0] total_bumps_needed,
output logic [CNT_W-1:0] spare_positions,
output logic requirement_fits,
// §4's closed form, as a PAIR. face/edge = L/(4p), published as
// numerator and denominator so no division happens here.
output logic [CNT_W-1:0] advantage_num,
output logic [CNT_W-1:0] advantage_den,
// ── Runtime query result.
output logic [CNT_W-1:0] q_face_positions,
output logic q_fits,
output logic q_out_valid,
output logic err_pitch_zero,
output logic err_pitch_exceeds_die,
output logic any_error
);
// Derived at elaboration. §3's model: a square grid over the face.
localparam int POS_PER_SIDE = DIE_SIDE_UM / PITCH_UM;
localparam int FACE_POS = POS_PER_SIDE * POS_PER_SIDE;
localparam int EDGE_POS = (4 * DIE_SIDE_UM) / PITCH_UM;
// §6: total = signals x (1 + PG_NUM/PG_DEN), computed without a
// real by scaling the numerator.
localparam int TOTAL_BUMPS = (SIGNAL_BUMPS * (PG_DEN + PG_NUM)) / PG_DEN;
initial begin
if (PITCH_UM < 1)
$fatal(1, "bump_connection_budget: PITCH_UM must be at least 1");
if (DIE_SIDE_UM < 1)
$fatal(1, "bump_connection_budget: DIE_SIDE_UM must be at least 1");
if (PITCH_UM > DIE_SIDE_UM)
// A pitch larger than the die holds zero positions, which is a
// misparameterisation rather than a very sparse die.
$fatal(1, "bump_connection_budget: PITCH_UM (%0d) exceeds DIE_SIDE_UM (%0d)",
PITCH_UM, DIE_SIDE_UM);
if (PG_DEN < 1 || PG_NUM < 0)
$fatal(1, "bump_connection_budget: power/ground ratio must be non-negative over a positive denominator");
if (SIGNAL_BUMPS < 1)
$fatal(1, "bump_connection_budget: SIGNAL_BUMPS must be at least 1");
if (POS_PER_SIDE < 1)
$fatal(1, "bump_connection_budget: pitch leaves fewer than one position per side");
// §6: the overhead must actually be counted. A block that
// reported a signals-only total would understate the field by
// whatever the power overhead is, which §6 says is the whole
// reason the ratio is a required input.
if (TOTAL_BUMPS < SIGNAL_BUMPS)
$fatal(1, "bump_connection_budget: total (%0d) below signal count (%0d)",
TOTAL_BUMPS, SIGNAL_BUMPS);
// §5's observation, enforced: the requirement should fit with
// room to spare at any sensible parameterisation. If it does not,
// the caller has chosen a pitch or a die that cannot work, and
// finding that at elaboration is the point.
if (TOTAL_BUMPS > FACE_POS)
$fatal(1, "bump_connection_budget: %0d bumps do not fit in %0d positions",
TOTAL_BUMPS, FACE_POS);
end
logic e_zero, e_big, qv;
logic [CNT_W-1:0] q_face;
logic q_ok;
// Declared above the continuous assigns that read them.
logic [CNT_W-1:0] q_per_side;
assign q_per_side = (q_pitch_um == '0) ? '0
: CNT_W'(CNT_W'(DIE_SIDE_UM) / CNT_W'(q_pitch_um));
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
e_zero <= 1'b0; e_big <= 1'b0; qv <= 1'b0;
q_face <= '0; q_ok <= 1'b0;
end else begin
e_zero <= 1'b0; e_big <= 1'b0; qv <= 1'b0;
if (q_valid) begin
if (q_pitch_um == '0) begin
// A zero pitch is not an infinitely dense surface, it is a
// division by zero. Reported, never computed.
e_zero <= 1'b1;
end else if ({{(32-16){1'b0}}, q_pitch_um} > CNT_W'(DIE_SIDE_UM)) begin
e_big <= 1'b1;
end else begin
q_face <= q_per_side * q_per_side;
q_ok <= (q_per_side * q_per_side) >= CNT_W'(TOTAL_BUMPS);
qv <= 1'b1;
end
end
end
end
assign face_positions = CNT_W'(FACE_POS);
assign edge_positions = CNT_W'(EDGE_POS);
assign total_bumps_needed = CNT_W'(TOTAL_BUMPS);
assign spare_positions = (FACE_POS >= TOTAL_BUMPS)
? CNT_W'(FACE_POS - TOTAL_BUMPS) : '0;
assign requirement_fits = (FACE_POS >= TOTAL_BUMPS);
// §4: face/edge = L/(4p). Published as the pair, never divided.
assign advantage_num = CNT_W'(DIE_SIDE_UM);
assign advantage_den = CNT_W'(4 * PITCH_UM);
assign q_face_positions = q_face;
assign q_fits = q_ok;
assign q_out_valid = qv;
assign err_pitch_zero = e_zero;
assign err_pitch_exceeds_die = e_big;
assign any_error = e_zero | e_big;
endmoduleThe advantage is published as L over 4p and never divided. §4's closed form is exact as a ratio and is rarely an integer — 10 mm over 180 µm is 55.6 — so dividing would force a rounding decision the caller is better placed to make. This is the same pair discipline 25.3 §12 and 26.1 §12 use.
And the requirement-fits check is at elaboration, not only at runtime. A parameterisation whose bump field does not fit its own die describes an assembly that cannot exist, and §5 established that the margin is normally around fifty times — so a failure means a parameter is wrong rather than a design being tight.
14. The Stack Layer Map
// ---------------------------------------------------------------------
// hbm_stack_layer_map -- the stack's layer structure: one base die at
// the bottom, N core dies above it, N from the verified height set.
//
// CLASSIFICATION: educational, synthesisable.
//
// WHAT IT DOES NOT MODEL:
// - the dies themselves, or anything physical. There is no
// thickness, no thermal path and no assembly step here.
// - the vertical connections (26.3 owns them entirely)
// - the base die's CONTENTS. §9's callout: 4.8 deferred "the
// stack's logic layer" to this module and this module could not
// deliver it. The block models the base die's POSITION and its
// SHARED status, which §9 derives from structure, and nothing
// about what is inside it.
//
// HEIGHTS ARE CURRICULUM-DERIVED from 4.8 §2: 2, 4, 8 and 12. A
// height outside that set is refused rather than accommodated,
// because accommodating it would imply a generality the source does
// not support.
// ---------------------------------------------------------------------
module hbm_stack_layer_map #(
parameter int CORE_DIES = 12, // CURRICULUM-DERIVED set (4.8 §2)
parameter int GB_PER_DIE2 = 16, // §8's inference: 16 Gb per core die
// Layers = core dies + one base die.
parameter int LAYERS = CORE_DIES + 1,
parameter int LAYER_IDX_W = $clog2(LAYERS),
// A COUNT up to LAYERS needs clog2(LAYERS+1).
parameter int LAYERCNT_W = $clog2(LAYERS + 1),
parameter int CAP_W = 16
) (
input logic clk,
input logic rst_n,
// ── Query a layer index.
input logic q_valid,
input logic [LAYER_IDX_W-1:0] q_layer,
output logic q_is_base,
output logic q_is_core,
output logic q_in_range,
// Core dies are numbered from the bottom upward, above the base.
output logic [LAYER_IDX_W-1:0] q_core_index,
// ── The structure, published.
output logic [LAYERCNT_W-1:0] n_layers,
output logic [LAYERCNT_W-1:0] n_core_dies,
output logic [LAYERCNT_W-1:0] n_base_dies,
// §8: height buys capacity, not bandwidth. Both are published so a
// consumer cannot infer one from the other by accident.
output logic [CAP_W-1:0] capacity_gb,
output logic [CAP_W-1:0] interface_bits,
output logic err_layer_out_of_range,
output logic any_error
);
initial begin
// CURRICULUM-DERIVED height set. A height outside it is refused.
if (!(CORE_DIES inside {2, 4, 8, 12}))
$fatal(1, "hbm_stack_layer_map: CORE_DIES must be 2, 4, 8 or 12 (4.8 §2), got %0d",
CORE_DIES);
if (LAYERS != CORE_DIES + 1)
// §7: exactly one base die, and it is not optional. A stack
// with no base die has no external interface at all.
$fatal(1, "hbm_stack_layer_map: LAYERS must be CORE_DIES + 1");
if (LAYERCNT_W <= LAYER_IDX_W && LAYERS > 1)
// COUNT vs INDEX. Too narrow and n_layers cannot represent the
// full height, so a consumer sees a shorter stack than exists.
$fatal(1, "hbm_stack_layer_map: LAYERCNT_W too narrow to count LAYERS");
// §8's identity: capacity is dies x per-die density, in GB.
if (((CORE_DIES * GB_PER_DIE2) / 8) > ((1 << CAP_W) - 1))
$fatal(1, "hbm_stack_layer_map: CAP_W too narrow for the capacity");
if ((CORE_DIES * GB_PER_DIE2) % 8 != 0)
// A capacity that is not a whole number of gigabytes means the
// per-die density and the height do not combine cleanly, which
// §8 verified they do for the published pair.
$fatal(1, "hbm_stack_layer_map: %0d dies x %0d Gb is not a whole number of GB",
CORE_DIES, GB_PER_DIE2);
end
logic e_range;
// Declared above the continuous assigns that read it.
logic in_rng;
assign in_rng = q_valid &&
({{(32-LAYER_IDX_W){1'b0}}, q_layer} < 32'(LAYERS));
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) e_range <= 1'b0;
else e_range <= q_valid && !in_rng;
end
// §7 and §9: layer 0 is the base die, at the bottom, because that
// is where the interposer is. Core dies are 1..CORE_DIES upward.
assign q_is_base = in_rng && (q_layer == '0);
assign q_is_core = in_rng && (q_layer != '0);
assign q_in_range = in_rng;
assign q_core_index = (q_layer == '0) ? '0 : (q_layer - LAYER_IDX_W'(1));
assign n_layers = LAYERCNT_W'(LAYERS);
assign n_core_dies = LAYERCNT_W'(CORE_DIES);
assign n_base_dies = LAYERCNT_W'(1);
assign capacity_gb = CAP_W'((CORE_DIES * GB_PER_DIE2) / 8);
// §8: the interface width does NOT depend on the height. Published
// as a constant beside the capacity so the independence is visible.
assign interface_bits = CAP_W'(1024);
assign err_layer_out_of_range = e_range;
assign any_error = e_range;
endmodulecapacity_gb and interface_bits are published side by side, and only one of them depends on the height. §8 established that height buys capacity and not bandwidth; putting both outputs on the same block makes the independence checkable rather than something a reader has to remember. P7 asserts it.
And exactly one base die is enforced rather than assumed. A stack parameterised with none would have no external interface and a stack with two would have two, neither of which §7's structure permits — so LAYERS == CORE_DIES + 1 is an elaboration condition rather than a convention.
15. The Bump Assignment Guard
// ---------------------------------------------------------------------
// bump_assignment_guard -- every bump position gets exactly one role,
// and the field is not complete until every signal has one.
//
// CLASSIFICATION: educational, synthesisable.
//
// WHAT IT DOES NOT MODEL:
// - any physical bump, its electrical behaviour or its placement
// - whether an assignment is MANUFACTURABLE. Placement rules,
// keep-outs and assembly tolerance are outside this block and
// outside this module's sources.
// - redundancy or repair. 26.3 owns spare connections and the
// repair map; this block has a SPARE role and no repair logic.
//
// WHY DOUBLE ASSIGNMENT IS THE FORBIDDEN ONE: a position assigned
// twice is not a conflict the hardware resolves -- it is two nets on
// one connection, which is a short. The block refuses the second
// assignment and reports it rather than overwriting the first.
// ---------------------------------------------------------------------
module bump_assignment_guard #(
parameter int POSITIONS = 2048,
parameter int SIGNALS = 1024, // CURRICULUM-DERIVED (4.8 §2)
parameter int POS_IDX_W = $clog2(POSITIONS),
// A COUNT up to POSITIONS needs clog2(POSITIONS+1).
parameter int POSCNT_W = $clog2(POSITIONS + 1),
parameter int SIGCNT_W = $clog2(SIGNALS + 1)
) (
input logic clk,
input logic rst_n,
// ── Assign a role to a position. Roles are exclusive.
input logic asg_valid,
input logic [POS_IDX_W-1:0] asg_pos,
input logic [1:0] asg_role, // 0 unassigned, 1 signal,
// 2 power/ground, 3 spare
output logic [POSCNT_W-1:0] n_assigned,
output logic [SIGCNT_W-1:0] n_signal,
output logic [POSCNT_W-1:0] n_power_ground,
output logic [POSCNT_W-1:0] n_spare,
output logic [POSCNT_W-1:0] n_unassigned,
// ── Completeness. §6: a field is not usable until every signal
// has a position, and the count is the only way to know.
output logic all_signals_assigned,
output logic field_complete,
output logic err_double_assignment,
output logic err_bad_role,
output logic err_pos_out_of_range,
output logic err_too_many_signals,
output logic any_error
);
localparam logic [1:0] R_NONE = 2'd0;
localparam logic [1:0] R_SIG = 2'd1;
localparam logic [1:0] R_PG = 2'd2;
localparam logic [1:0] R_SPR = 2'd3;
initial begin
if (POSITIONS < 2)
$fatal(1, "bump_assignment_guard: POSITIONS must be at least 2");
if (SIGNALS < 1 || SIGNALS > POSITIONS)
// More signals than positions is not a tight design, it is an
// impossible one.
$fatal(1, "bump_assignment_guard: SIGNALS (%0d) must be 1..POSITIONS (%0d)",
SIGNALS, POSITIONS);
if (POS_IDX_W != $clog2(POSITIONS))
$fatal(1, "bump_assignment_guard: POS_IDX_W must address POSITIONS");
if (POSCNT_W <= POS_IDX_W)
$fatal(1, "bump_assignment_guard: POSCNT_W too narrow to count POSITIONS");
end
logic [1:0] role [POSITIONS];
logic [SIGCNT_W-1:0] c_sig;
logic [POSCNT_W-1:0] c_pg, c_spr;
logic e_dbl, e_role, e_rng, e_many;
// Declared above the continuous assigns that read them.
logic pos_ok;
assign pos_ok = ({{(32-POS_IDX_W){1'b0}}, asg_pos} < 32'(POSITIONS));
logic role_ok;
assign role_ok = (asg_role != R_NONE);
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
for (int i = 0; i < POSITIONS; i++) role[i] <= R_NONE;
c_sig <= '0; c_pg <= '0; c_spr <= '0;
e_dbl <= 1'b0; e_role <= 1'b0; e_rng <= 1'b0; e_many <= 1'b0;
end else begin
e_dbl <= 1'b0; e_role <= 1'b0; e_rng <= 1'b0; e_many <= 1'b0;
if (asg_valid) begin
if (!pos_ok) begin
e_rng <= 1'b1;
end else if (!role_ok) begin
// "Unassigned" is a state, not a role to assign. Accepting
// it would let a caller silently un-assign a position and
// make the completeness count drift.
e_role <= 1'b1;
end else if (role[asg_pos] != R_NONE) begin
// Already assigned: refuse and report. Overwriting would
// hide two nets competing for one connection.
e_dbl <= 1'b1;
end else if ((asg_role == R_SIG) && (c_sig == SIGCNT_W'(SIGNALS))) begin
// More signal assignments than the interface has signals.
e_many <= 1'b1;
end else begin
role[asg_pos] <= asg_role;
unique case (asg_role)
R_SIG : c_sig <= c_sig + SIGCNT_W'(1);
R_PG : c_pg <= c_pg + POSCNT_W'(1);
R_SPR : c_spr <= c_spr + POSCNT_W'(1);
default : ;
endcase
end
end
end
end
assign n_signal = c_sig;
assign n_power_ground = c_pg;
assign n_spare = c_spr;
assign n_assigned = POSCNT_W'(c_sig) + c_pg + c_spr;
assign n_unassigned = POSCNT_W'(POSITIONS) - n_assigned;
assign all_signals_assigned = (c_sig == SIGCNT_W'(SIGNALS));
// Complete means every signal placed. Spare and unassigned
// positions are fine; a missing signal is not.
assign field_complete = all_signals_assigned;
assign err_double_assignment = e_dbl;
assign err_bad_role = e_role;
assign err_pos_out_of_range = e_rng;
assign err_too_many_signals = e_many;
assign any_error = e_dbl | e_role | e_rng | e_many;
endmoduleA double assignment is refused, not overwritten. Overwriting would leave the first net believing it has a connection and the second actually having it — and the counts would still look correct, because one position would hold one role. Refusing keeps the error visible in the cycle it happens, which is the only cycle in which it is cheap.
And field_complete depends on signals only. Unassigned and spare positions are expected — §5 established the field uses about 2% of the face — so requiring full assignment would make completeness unreachable. A missing signal, by contrast, is an interface that cannot work, which is why that is the condition the flag tracks.
16. What the Assertions Prove
// Bind unit note: P1-P5 reference bump_connection_budget's internals,
// P6-P9 hbm_stack_layer_map's, P10-P14 bump_assignment_guard's.
// P1 -- §3's model, as an invariant: the face count is the positions
// per side squared, and never exceeds what the area can hold.
property p_face_count_is_grid_squared;
@(posedge clk) disable iff (!rst_n)
(face_positions == CNT_W'((DIE_SIDE_UM / PITCH_UM) * (DIE_SIDE_UM / PITCH_UM)));
endproperty
assert property (p_face_count_is_grid_squared);
// P2 -- §4's closed form, as a published pair: the advantage is the
// die side over four times the pitch, never a divided scalar.
property p_advantage_is_side_over_four_pitch;
@(posedge clk) disable iff (!rst_n)
((advantage_num == CNT_W'(DIE_SIDE_UM)) &&
(advantage_den == CNT_W'(4 * PITCH_UM)));
endproperty
assert property (p_advantage_is_side_over_four_pitch);
// P3 -- §4: the face always beats the edge for a die larger than four
// pitches. Stated as the count comparison rather than the ratio, so
// it is checkable without dividing.
property p_face_beats_edge;
@(posedge clk) disable iff (!rst_n)
((DIE_SIDE_UM > 4 * PITCH_UM) |-> (face_positions > edge_positions));
endproperty
assert property (p_face_beats_edge);
// P4 -- §6: the total always includes the power and ground overhead,
// so it is never below the signal count.
property p_total_includes_overhead;
@(posedge clk) disable iff (!rst_n)
(total_bumps_needed >= CNT_W'(SIGNAL_BUMPS));
endproperty
assert property (p_total_includes_overhead);
// P5 -- FORBIDDEN. A zero pitch never produces a count. It is a
// division by zero, not an infinitely dense surface.
property p_zero_pitch_never_computes;
@(posedge clk) disable iff (!rst_n)
(q_valid && (q_pitch_um == '0)) |=> (err_pitch_zero && !q_out_valid);
endproperty
assert property (p_zero_pitch_never_computes);
// P6 -- exactly one base die, always. §7: a stack without one has no
// external interface at all.
property p_exactly_one_base_die;
@(posedge clk) disable iff (!rst_n)
((n_base_dies == LAYERCNT_W'(1)) &&
(n_layers == n_core_dies + LAYERCNT_W'(1)));
endproperty
assert property (p_exactly_one_base_die);
// P7 -- §8's separation: the interface width does not depend on the
// stack height. The property that makes "height buys capacity, not
// bandwidth" checkable rather than memorable.
property p_interface_width_is_height_independent;
@(posedge clk) disable iff (!rst_n)
(interface_bits == CAP_W'(1024));
endproperty
assert property (p_interface_width_is_height_independent);
// P8 -- §8's identity: capacity is core dies times per-die density.
property p_capacity_is_dies_times_density;
@(posedge clk) disable iff (!rst_n)
(capacity_gb == CAP_W'((CORE_DIES * GB_PER_DIE2) / 8));
endproperty
assert property (p_capacity_is_dies_times_density);
// P9 -- base and core are mutually exclusive and exhaustive over an
// in-range layer. A layer that is neither would be unaccounted.
property p_layer_roles_partition;
@(posedge clk) disable iff (!rst_n)
(q_in_range |-> (q_is_base ^ q_is_core));
endproperty
assert property (p_layer_roles_partition);
// P10 -- FORBIDDEN. A position is never assigned twice. §15: that is
// two nets on one connection, not a resolvable conflict.
property p_no_double_assignment;
@(posedge clk) disable iff (!rst_n)
(asg_valid && (asg_role != 2'd0) &&
({{(32-POS_IDX_W){1'b0}}, asg_pos} < 32'(POSITIONS)) &&
(role[asg_pos] != 2'd0))
|=> (err_double_assignment && (n_assigned == $past(n_assigned, 1)));
endproperty
assert property (p_no_double_assignment);
// P11 -- the role counts partition the assigned positions exactly.
property p_role_counts_partition;
@(posedge clk) disable iff (!rst_n)
((POSCNT_W'(n_signal) + n_power_ground + n_spare) == n_assigned);
endproperty
assert property (p_role_counts_partition);
// P12 -- assigned and unassigned partition every position.
property p_positions_fully_accounted;
@(posedge clk) disable iff (!rst_n)
((n_assigned + n_unassigned) == POSCNT_W'(POSITIONS));
endproperty
assert property (p_positions_fully_accounted);
// P13 -- FORBIDDEN. The signal count never exceeds the interface's
// signal requirement.
property p_signal_count_bounded;
@(posedge clk) disable iff (!rst_n)
(n_signal <= SIGCNT_W'(SIGNALS));
endproperty
assert property (p_signal_count_bounded);
// P14 -- FORBIDDEN. The field is never complete while a signal is
// unassigned. §15: spare and unassigned positions are fine; a
// missing signal is an interface that cannot work.
property p_never_complete_with_a_missing_signal;
@(posedge clk) disable iff (!rst_n)
(field_complete |-> (n_signal == SIGCNT_W'(SIGNALS)));
endproperty
assert property (p_never_complete_with_a_missing_signal);
// ── Cover.
// A runtime pitch query answered, at a finer and a coarser pitch.
cover property (@(posedge clk) disable iff (!rst_n) q_out_valid && q_fits);
cover property (@(posedge clk) disable iff (!rst_n) q_out_valid && !q_fits);
// Each forbidden condition ATTEMPTED -- vacuous otherwise.
cover property (@(posedge clk) disable iff (!rst_n) err_pitch_zero);
cover property (@(posedge clk) disable iff (!rst_n) err_pitch_exceeds_die);
cover property (@(posedge clk) disable iff (!rst_n) err_double_assignment);
cover property (@(posedge clk) disable iff (!rst_n) err_bad_role);
cover property (@(posedge clk) disable iff (!rst_n) err_too_many_signals);
// Every layer role reached, at the bottom and the top of the stack.
cover property (@(posedge clk) disable iff (!rst_n) q_is_base);
cover property (@(posedge clk) disable iff (!rst_n)
q_is_core && (q_core_index == LAYER_IDX_W'(CORE_DIES - 1)));
// Every bump role actually assigned.
cover property (@(posedge clk) disable iff (!rst_n) n_signal != '0);
cover property (@(posedge clk) disable iff (!rst_n) n_power_ground != '0);
cover property (@(posedge clk) disable iff (!rst_n) n_spare != '0);
// THE COMPLETENESS COVER: every signal placed, with spare and
// unassigned positions remaining -- §5's 2% occupancy as a state.
cover property (@(posedge clk) disable iff (!rst_n)
field_complete && (n_unassigned != '0));
// And the near-miss: every position assigned except one signal.
cover property (@(posedge clk) disable iff (!rst_n)
!field_complete && (n_signal == SIGCNT_W'(SIGNALS) - 1));17. Corner Cases
| Case | Behaviour | Why |
|---|---|---|
| Pitch of 0 | $fatal at elaboration; reported at runtime | A division by zero, not infinite density |
| Pitch larger than the die | $fatal at elaboration | Zero positions is a misparameterisation |
| Pitch leaving under one position per side | $fatal at elaboration | The grid model degenerates |
| Total bumps exceeding face positions | $fatal at elaboration | §5 — the normal margin is ~50×, so this means a wrong parameter |
| Signals-only total with a non-zero ratio | $fatal at elaboration | §6 — would understate the field |
| Runtime query at a coarser pitch that no longer fits | q_fits low; no error | A legitimate answer to a legitimate question |
| Die exactly four pitches wide | Face equals edge; P3's antecedent false | The one size where the closed form gives 1 |
| Stack height of 6 | $fatal at elaboration | Outside 4.8 §2's verified set |
| Stack with no base die | $fatal at elaboration | P6 — no external interface exists |
| Height changed from 2 to 12 | Capacity scales; interface_bits unchanged | §8, P7 — height buys capacity, not bandwidth |
| Per-die density not dividing into whole GB | $fatal at elaboration | §8 verified the published pair divides cleanly |
| Position assigned twice | Refused and reported; counts unchanged | P10 — two nets on one connection |
| Role “unassigned” supplied as an assignment | err_bad_role | It is a state, not a role; accepting it would drift the counts |
More signal assignments than SIGNALS | err_too_many_signals | P13 |
| Field complete with spare and unassigned left | Normal — the expected state | §5's 2% occupancy; P14 cares only about signals |
| Every position assigned but one signal missing | Not complete | P14 — a full field with a missing signal cannot work |
POSCNT_W too narrow for POSITIONS | $fatal at elaboration | COUNT vs INDEX; completeness would be unreachable |
Rows fifteen and sixteen are the pair worth holding together. A field with unused positions is healthy and a field with no unused positions can still be broken, because completeness is about the signals and not about the occupancy.
18. DV
// Independent geometry reference. Computes counts by explicitly
// walking a grid rather than by multiplying, so agreement with the
// DUT is evidence rather than a restatement of the same product.
// SIMULATION-ONLY.
class bump_geometry_ref;
int side_um, pitch_um;
function void build(int side, int pitch);
side_um = side; pitch_um = pitch;
endfunction
// Walk the grid. Deliberately O(n) rather than a squared product.
function int face_positions();
int n = 0;
for (int x = 0; x + pitch_um <= side_um; x += pitch_um)
for (int y = 0; y + pitch_um <= side_um; y += pitch_um)
n++;
return n;
endfunction
// Walk the perimeter as four sides.
function int edge_positions();
int n = 0;
for (int s = 0; s < 4; s++)
for (int x = 0; x + pitch_um <= side_um; x += pitch_um)
n++;
return n;
endfunction
// §4's closed form, as a pair -- never a real.
function void advantage(output int num, output int den);
num = side_um;
den = 4 * pitch_um;
endfunction
// §6: signals plus overhead expressed as a ratio.
function int total_bumps(int signals, int pg_num, int pg_den);
return (signals * (pg_den + pg_num)) / pg_den;
endfunction
endclass| Check | What it establishes |
|---|---|
Reference face_positions() against the DUT at three pitches | §3's model, by walking rather than multiplying |
Reference edge_positions() against the DUT | §4's denominator, independently counted |
Confirm face/edge equals the reference advantage() pair | §4's closed form, at every pitch |
| Sweep pitch and confirm halving it roughly quadruples the face count | §3's quadratic exponent, measured |
| Sweep pitch and confirm the advantage ratio doubles | §4's linear-in-pitch behaviour |
| Set the die to exactly four pitches; confirm face equals edge | §17's row seven, the boundary of P3 |
| Query a pitch of zero | P5 and err_pitch_zero |
| Query a pitch above the die side | err_pitch_exceeds_die |
Reference total_bumps() at 1:0, 1:1 and 1:2 | §6's table, independently computed |
| Parameterise heights 2, 4, 8, 12 and confirm the capacity table | §8, P8 |
| Parameterise height 6 | Elaboration fails rather than interpolating |
Change the height and watch interface_bits | P7 — it must not move |
| Assign every position once, then repeat one | P10; counts frozen on the repeat |
Assign SIGNALS signals then one more | err_too_many_signals; P13 |
| Assign all but one signal, then check completeness | P14; field_complete low |
The twelfth check produces the report worth publishing, because the mistake it catches is one a datasheet reader makes rather than a coder:
THE HEIGHT THAT WAS ASSUMED TO BUY BANDWIDTH
Parameterise the stack at 2, 4, 8 and 12 core dies and read both
published outputs.
CORE_DIES capacity_gb interface_bits
2 4 1024
4 8 1024
8 16 1024
12 24 1024
P7 interface_width_is_height_independent PASS at every height
P8 capacity_is_dies_times_density PASS at every height
what a reader expecting otherwise would predict:
"a 12-high stack has six times the dies of a 2-high stack,
so it should deliver more bandwidth"
diagnosis : it delivers exactly the same bandwidth. The
interface is 1024 bits wide regardless of how many dies sit
behind it, because the width is a property of the base die and
the interposer -- not of the stack.
why the mistake is easy : capacity and bandwidth are both
"more memory", both scale with money, and both appear in the
same product brief. Only one of them scales with height.
the consequence, which 26.4 develops : an accelerator that needs
more bandwidth must add STACKS, and one that needs more
capacity can add DIES. Those are different purchases with
different costs, and confusing them produces a system that is
expensive in the wrong dimension.
the fix : publish both outputs from one block (§14) so the
independence is visible in the interface rather than
remembered from prose.19. Debugging
| Symptom | Likely cause | How to confirm |
|---|---|---|
| Bump field will not fit | Pitch too coarse for the requirement | The $fatal names both counts; §5's margin is normally ~50× |
| Field fits but the interposer is still large | The interposer is sized by the dies on it, not the bumps — §5 | Compare need against the die footprints |
| Connection budget looks generous, design still constrained | The limit is yield or thermal, not geometry — §5's callout | Neither is computable here; 4.8 §3 owns the argument |
| Bump count understated | Power and ground overhead omitted — §6 | total_bumps_needed against SIGNAL_BUMPS; P4 |
| Adding dies did not raise bandwidth | Expected — §8, §18 | interface_bits is constant; P7 |
| Capacity not a whole number of GB | Per-die density and height do not combine — §8 | The elaboration guard |
| Two nets on one connection | Double assignment overwritten instead of refused | err_double_assignment; P10 |
| Field reports complete but a net is missing | Completeness tracked over positions, not signals | P14 — it must depend on n_signal only |
| Counts drift over a long assignment run | “Unassigned” accepted as a role | err_bad_role |
| Advantage ratio looks wrong | Divided instead of published as a pair | P2 — L / 4p is rarely an integer |
Row three is the entry this chapter exists to add. A comfortable connection budget does not mean a comfortable design — §5 establishes that the geometric wall is answered with about fifty times the margin, and that HBM's remaining costs are of an entirely different kind.
Row five is the one that reads as a fault and is not. Adding dies to a stack does not add bandwidth, and a system expecting otherwise has bought the wrong thing.
20. Misconceptions
“The interposer helps because the traces are short.” §2. Shortness helps energy and signal quality. Density is what makes the interface possible at all — at a board's wiring density, short traces would leave the wall exactly where it was.
“Pitch and area are equally useful levers.” §3. The count is A / p² — quadratic in pitch, linear in area. Halving the pitch does what quadrupling the area does, without growing the die.
“The face-versus-edge advantage depends on the pitch in a complicated way.” §4. It is L / 4p — the pitch cancels from quadratic to linear, and the whole comparison is one division.
“A bigger die is harder to connect.” §4. On the edge, yes — 26.1 §1's 4/L. On the face, a bigger die gains more, because L / 4p is linear in L. Same fact, opposite sign.
“A thousand connections needs a lot of area.” §5. Under two millimetres square at every pitch in the table — about 2% of a 10 mm die's face.
“So the bump count is what limits HBM.” §5's callout. It is not, by roughly fifty times. The remaining costs are yield, assembly and thermal, and 4.8 §3 owns that argument.
“Signal count sizes the bump field.” §6. Power and ground need bumps too, and the overhead ratio is a required input — §13 refuses to guess it.
“Overhead is expensive in area.” §6. Tripling the bump count raises the side length by only √3. Overhead is costly in count and cheap in linear dimension.
“A taller stack is faster.” §8. Height buys capacity. The interface is 1024 bits wide at every height, and §18's report shows the table.
“HBM uses exotic dies.” §8. Chapter 4.8's published capacity and height imply a 16 Gb core die exactly — an ordinary density. Stacking combines ordinary dies.
“2.5D is a step on the way to 3D.” §10. It is a distinct choice: take the interposer's density, decline the thermal and yield coupling of stacking logic on memory.
“The processor is in the stack.” §10, §11. It sits beside the interposer's stack. A diagram with the processor above or below the DRAM is the 3D arrangement.
“This chapter verified HBM's bump pitch.” The provenance callout. Every pitch here is illustrative. No pitch, bump count or dimension was verified from any source.
21. Interview Reasoning
Which property of a silicon interposer makes HBM possible? Wiring density. Short traces improve energy and signal quality, but at a board's density the connection count would be exactly as limited as before — the wall is about how many connections can exist.
How do you turn a bump pitch into a connection count? Area over pitch squared, for a square grid. So the count is quadratic in pitch and linear in area, which makes pitch the stronger lever.
Derive the face-versus-edge advantage. Face is L²/p², edge is 4L/p, so the ratio is L/4p. At a 10 mm die and 45 µm pitch that is about 56×.
Does a bigger die help or hurt? Both, depending on the surface. On the edge, connections per unit capability fall as 4/L. On the face, the advantage over the edge grows as L/4p. The same geometry read from either side.
How much area does a 1024-bit interface's bump field need? Under two millimetres square at plausible pitches — roughly 2% of a 10 mm die's face. The count is not the constraint.
Then what is the constraint? Not geometry. Yield, assembly and thermal limits — and a defect at assembly scraps a unit containing an expensive processor, which is the cost structure that keeps HBM in applications that justify it.
Does the signal count size the bump field? No — power and ground need bumps too. The overhead ratio must be supplied, and at two power-and-ground bumps per signal the field is about 2.5 mm square rather than 1.4 mm.
What does a taller stack buy? Capacity, not bandwidth. The interface is 1024 bits wide regardless of height, so more bandwidth means more stacks and more capacity means more dies.
What does 2.5D mean, precisely? Dies side by side on a silicon interposer, with stacking inside the memory only. The processor is a neighbour, not a layer — which keeps their thermal paths and their yields separate.
Why not stack the processor on the memory? It combines the worst thermal arrangement with the most temperature-sensitive part, since DRAM retention falls as temperature rises — and it couples two dies' yields that are otherwise only joined at assembly.
22. Exercises
-
Derive the connection count for a hexagonal grid rather than a square one, and compute the improvement factor over §3's model. State the assumption that makes it an upper bound.
-
§4 gives the advantage as
L/4p. Derive the equivalent for a die connected on two edges rather than four, and say at what die size the face still wins. -
Using §5's figures, compute the fraction of a 10 mm die's face consumed by a 1024-bit interface at each pitch in the table. Then compute the pitch at which it would consume half the face, and comment on whether that is a meaningful limit.
-
§6 shows overhead is cheap in linear dimension. Derive the general relationship between a bump-count multiplier and the side-length multiplier, and use it to explain why very high overhead ratios are geometrically tolerable.
-
Remove §13's elaboration check that the total fits the face, and parameterise a 1 mm die at 55 µm pitch with a 1:2 ratio. Which properties fire, and which do not?
-
§14 publishes
capacity_gbandinterface_bitsfrom one block. Construct the argument for separating them into two blocks, then the argument against, and say which §18's report supports. -
§8 infers a 16 Gb core die from two of 4.8's figures. Identify every other core-die density consistent with one of those figures alone, and say what the second figure eliminates.
-
§15's
field_completeignores spare and unassigned positions. Construct a bump field that satisfies P14 and is nonetheless unusable, and say which layer of the design would have to catch it.
23. Where This Goes
The surface is now a count. A pitch converts an area into connections as A/p²; the face beats the edge by exactly L/4p, which is between 23 and 200 times at every plausible parameterisation; a 1024-bit bump field is under two millimetres square and uses about 2% of a 10 mm die's face; and the stack above it is one base die plus 2, 4, 8 or 12 ordinary 16 Gb core dies.
Four results carry forward. Density rather than shortness is the interposer's enabling property, which is why the chapter is about pitch and not about length. The face-versus-edge advantage has a closed form in which the pitch cancels from quadratic to linear, and the advantage grows with die size — the exact inverse of 26.1 §1's edge result. The bump count is not HBM's constraint, by roughly fifty times, which relocates the real cost to yield, assembly and thermal limits that this module cannot compute. And height buys capacity, not bandwidth — an independence §18's report makes visible and 26.4 builds on.
Two things are left open, and the second is this module's largest gap.
Every pitch in this chapter is illustrative. The geometry is general and the values are examples — The provenance callout records that no pitch, bump count or dimension was verified from any source, because JEDEC refused every retrieval and both vendor briefs yielded no usable text.
And the base die's contents remain undelivered. Chapter 4.8's scope callout assigns “the stack's logic layer” to this module, and §9 could only state what the base die's position and shared status imply. Its actual function — what logic it holds, whether it holds any array, what it does at initialisation and test — is a deferred topic this module cannot close. That is a whole subject rather than a detail, and naming it as unclosed is more useful than filling it with plausible architecture.
What both chapters so far have assumed is the vertical connection itself. §3 counted positions on a face and §11 drew microbumps joining a stack to an interposer, but nothing has said what actually passes through a die to reach the one above it. Chapter 26.1 §1's callout named it as the mechanism that changes the exponent, and 4.8 §1 describes it in one clause: “conductors passing vertically through the body of each die.”
Chapter 26.3 takes that up — what a through-silicon via is, how many a stack needs given the hierarchy 26.1 established, why a stack of them needs spares in a way a planar interface never did, and how a repair map turns a defective connection into a working stack. It is also the chapter where the temptation to compute physics is strongest, and where the RTL-discipline callout of this chapter matters most.
Continue learning
Related tutorials
- Related topic
HBM Overview
HBM reaches hundreds of GB/s with a per-pin rate lower than DDR5's. It wins on width, not speed — and getting that width required changing the packaging, which adds a fourth design layer to array physics, device architecture and the interface.
- Related topic
Why HBM Exists
Connections scale with perimeter while capability scales with area, and the ratio falls as 4/L. The width that answers it divides into sixteen streams that preserve the 64-byte granule exactly.
- Related topic
Through-Silicon Vias (TSVs)
At a per-via reliability of one in ten thousand, a twelve-high stack works 2.5% of the time. One spare per group of 64 removes 99.7% of that risk — and 48 spares tolerate between 2 and 48 failures.
- Related topic
HBM for AI Accelerators
Stacks buy bandwidth and dies buy capacity. The same 96 GB bought as twelve short stacks delivers three times the bandwidth of four tall ones — and one requester cannot use any of it.
Standards & specifications
- Governing standard
- JEDEC JESD79 (DDR SDRAM)(opens JEDEC Solid State Technology Association in a new tab)
Defines the DDR SDRAM device itself — signals, command encoding, mode registers, timing parameters and the initialisation sequence — one document per generation. Memory-controller microarchitecture, address-mapping policy, PHY training algorithms and board-level design are not specified by it.
This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.
Where this fits
Part of the DDR curriculum.
