5.3.6 · D5Advanced Microarchitecture

Question bank — Reservation stations

2,428 words11 min readBack to topic

Before you start, we build every symbol used below from scratch — do not skip this, the traps depend on it.

Three plain-word anchors to keep in mind:

  • A tag is the name of a desk (an RS) that will produce a value — never the name of a register.
  • The Common Data Bus (CDB) is the shout: one broadcast wire carrying (tag, value) that every desk and the register file listens to at once.
  • Snooping means passively listening on the CDB and comparing the broadcast tag against your own Qj/Qk.

The figure below fixes all of this in one picture — refer back to it as you work through the traps.

Figure — Reservation stations

The "spot the error" section relies on one tiny self-contained trace. Here it is in full so you never have to leave this page:

Figure — Reservation stations

True or false — justify

Every answer must give the reason, not just T/F.

An RS can hold an instruction whose operands are not yet computed.
True — that is the whole point. It stores tags (Qj/Qk) pointing at the desks that will produce those operands and waits for the CDB shout, rather than stalling the pipeline.
Reservation stations eliminate every kind of hazard.
False — renaming removes the false register hazards WAR and WAW; true RAW dependencies are not removed but are correctly enforced by the tag-and-capture machinery. Memory-aliasing, control (branch), and structural (RS-full) hazards also remain. See 5.3.09-Load-store-queues for memory disambiguation.
Register renaming, by itself, removes RAW hazards too.
False — a RAW is a genuine data dependency (you need the real value), so it cannot be renamed away. Renaming only kills the false name-collisions WAR and WAW; the RS still stalls the consumer until the producer broadcasts.
A tag stored in Qj is the number of a physical register.
False — the tag names the producing reservation station, which is transient and freed after write-back. In classic Tomasulo the RS itself acts as the renamed register during flight.
Two different reservation stations can be waiting on the same tag at the same time.
True — many consumers can hold the same Qj/Qk tag; when that tag broadcasts, all of them capture the value simultaneously. This is exactly why broadcasting beats point-to-point delivery.
Classic Tomasulo can write back two functional-unit results in the same cycle.
False — there is a single CDB, so only one result broadcasts per cycle; simultaneous completions create a structural hazard resolved by arbitration.
Once an operand value is in Vj, the corresponding Qj still matters.
False — readiness is decided by Qj = 0 (no pending tag). A non-zero Qj and a stored Vj are mutually exclusive; capturing a value sets Qj to 0.
The register status table can point two different registers to the same RS tag.
False — each RS produces exactly one result, so at most one register's status entry names a given tag as "next producer". Multiple consumers can hold the tag, but only one register status slot binds to it.
An empty register-status entry means "this register never had a value".
False — an empty entry means the current value already lives in the register file and is ready to read; nothing is pending for it.
If all reservation stations attached to a functional unit are busy, instruction issue must stall.
True — this is a structural hazard on the RS resource itself; without a free desk, decode cannot allocate, so issue blocks even if the FU is idle.
Renaming through RS tags requires physically copying register values around.
False — renaming is done by pointing: the status table records which tag will produce the register's next value. Values move only once, on the CDB broadcast.

Spot the error

Each line states a flawed claim or a broken trace step; the reveal names what is wrong and why. All refer to the reference trace above.

"During Issue, we wait until both operands are ready before allocating an RS."
Wrong — allocation happens first, regardless of operand readiness; the waiting for Qj = Qk = 0 happens in the Execute stage. Issue never blocks on operand availability, only on a free RS.
"When Mult1 finishes, the register file always writes R1."
Wrong — the register file only writes if Status[R1] still equals Mult1. After I3 overwrote it to Add2 (a WAW), Mult1's value is dead and the file ignores it.
"Instruction I2 eventually captures instruction I3's newer R1."
Wrong — I2 snapshotted the Mult1 tag at its issue time, before I3 existed. It waits for Mult1's value forever; temporal ordering is frozen at tag capture.
"Because tags rename registers, tag width equals the number of architectural registers."
Wrong — tag width is , sized to the number of stations, not architectural registers.
"An RS is freed the moment it starts executing on the functional unit."
Wrong — it is freed only after Write Result (after it broadcasts on the CDB). Freeing at execute-start would drop the result before consumers could capture it.
"We broadcast results point-to-point to exactly the RSs that need them, saving bus wires."
Wrong — at issue time we don't yet know all future consumers (dependencies are dynamic), so we must broadcast to everyone; that unknown consumer set is the reason a shared bus exists.
"Snooping the CDB means each RS asks the CDB every cycle whether its operand is ready."
Wrong — snooping is passive: every RS listens to the single broadcast and compares the broadcast tag against its own Qj/Qk. There is no polling request.

Why questions

Explain the mechanism, not just restate the rule.

Why do reservation stations distribute dependency tracking instead of using one central queue?
A central queue makes every instruction check every other instruction's dependencies ( interaction); giving each RS its own operand fields lets a station track only its own two tags, so the work scales with the local instruction, not the whole window. Contrast 5.3.04-Scoreboarding.
Why does overwriting Status[R1] on a later write eliminate the WAW hazard?
Because the status table always names the latest producer of a register; once overwritten (I3 → Add2), the earlier producer's completion (Mult1) no longer matches the status, so its result is silently discarded — making the older write invisible.
Why is the WAR hazard eliminated automatically by tag capture?
An earlier reader has already grabbed either the old value or the old producing tag at its issue time; a later writer changes only the status binding for future readers, so it cannot clobber a value the earlier reader depended on. This is the renaming idea in 5.2.03-Register-renaming.
Why must the CDB carry a tag alongside the value, not just the value?
The value alone is ambiguous — many desks might be waiting on different producers. The tag lets each snooping RS decide whether this shout is for me by matching against its Qj/Qk.
Why can reservation stations enable out-of-order completion but not fully out-of-order commit safely?
RS let instructions execute and write results as operands arrive (any order), but precise exceptions need results retired in program order — which is why a 5.3.07-Reorder-buffer is added on top of the RS machinery.
Why does adding a second CDB increase cost more than linearly in the design?
Every extra bus must be snooped by every operand field of every RS and the register file, so wiring and comparator count grow with (buses × stations), an blow-up, plus arbitration logic to pick which FU uses which bus.
Why does a load compute its address in the Execute stage rather than at Issue?
The base register may still be pending at issue; address computation must wait until the base operand's tag clears (Qj = 0), just like any arithmetic operand, before the memory access can begin.

Edge cases

Boundary and degenerate scenarios the main flow glosses over.

An instruction with both operands already in the register file — what happens in Execute?
It issues, finds Qj = Qk = 0 immediately (values sat in Vj/Vk at issue), and can execute on the very next cycle with no waiting; the RS acts as a pure pass-through.
An instruction that reads a register never written by any in-flight instruction.
Status for that register is empty, so the value is copied straight from the register file into Vj/Vk at issue with no tag — the safe default path.
What if a producing RS and a consuming instruction issue in the same cycle before any broadcast?
The consumer reads the status table, sees the producer's tag, and stores it in Qj/Qk; it waits for the future CDB shout. No value exists yet, so it correctly binds by tag, not value.
Two instructions write the same register back-to-back, and the first never has any consumer.
The first still executes and broadcasts, but since its status was overwritten (WAW) and no RS holds its tag, its result matches nothing and is dropped — wasted work but correct state.
An instruction whose result is needed by nobody (dead value).
It still occupies an RS, executes, broadcasts on the CDB, and frees its station; no consumer captures it and the register file writes only if its status still matches. Correctness is preserved; only the resource is briefly spent.
The RS pool for a functional unit is size zero (degenerate design).
No instruction targeting that FU can ever issue — every such decode stalls permanently, showing that RS count directly bounds achievable parallelism (typical designs use 5–10 integer, 8–15 FP).
A branch mispredicts while several RS are mid-flight.
Their in-flight results are on the wrong path and must be squashed; RS alone cannot do this cleanly, which is why recovery relies on the 5.3.07-Reorder-buffer and branch-prediction machinery, per 4.6.02-Pipeline-hazards.
Two loads to the same memory address where one is older but issues its address later.
RS do not disambiguate memory — they track only register tags. Ordering these requires a 5.3.09-Load-store-queues; assuming RS handle it is the classic memory-aliasing trap.
Recall One-line self-test

Give the single fact that most often gets stated backwards on this topic. A tag names a reservation station (the producer's desk), never a register number — everything else follows from that.

Connections