RTL Review

← 01 RTL Fundamentals and SV Coding | Index | 03 CDC, Reset and Async Design →

Round 02 — Combined answers (Gemini · GPT · Claude)

Contents

0. Resume probe

M2Q1 · "Your resume says you removed a multicycle path. Why was it there, why was it bad, and what did removing it cost?"

Gemini Answer

GPT Answer

"I re-architected the Tx length-parameter datapath for Wi-Fi 7 MU-MIMO/MU-OFDMA and re-pipelined it to remove the legacy multicycle path. The key tradeoff is added latency and registers versus simpler single-cycle timing contracts. I would explain the actual stage boundaries and timing evidence from the project; those details and its clock frequency are not in my resume."

Claude Answer

"The legacy Tx length-parameter block computed N_SYM, the LDPC extra-symbol decision and
TXTIME combinationally from the registered PPDU parameters. It was too deep for one cycle,
and because a new PPDU only starts every SIFS or longer, the original designer constrained
it as a 3-cycle multicycle path instead of pipelining it. That was bad for three reasons:
the constraint lived in an SDC that had to survive SoC integration and hierarchy changes;
the -hold side was easy to get wrong, and PD got it wrong twice; and nothing in the RTL
enforced the 3-cycle stability assumption, so any new consumer sampling early, or Wi-Fi 7's
per-user MU loop re-driving the inputs, could silently break it. Removing it cost about
ten extra pipeline cycles of latency (tens of ns against a 16 µs SIFS budget), a few hundred
flops, and a verification effort: I kept the old combinational block as the golden model and
compared every output across the full rate matrix. In exchange the block became
single-cycle constrained, retime-free and integrator-proof."

Part A — Rapid-fire Q and A (0:05–0:20)

M2Q2 · A1. Write the setup and hold inequalities including clock skew and uncertainty. Which one does a faster clock make worse, and which one is frequency-independent?

Gemini Answer

GPT Answer

With skew = capture_arrival - launch_arrival: setup is tcq_max + data_max + setup <= T + skew - Usetup; hold is tcq_min + data_min >= hold + skew + Uhold. Increasing frequency worsens setup; ordinary same-edge hold does not depend on period.

Claude Answer

Setup: t_cq(max) + t_logic(max) + t_setup ≤ T + (t_skew_capture − t_skew_launch) − t_uncertainty.
Hold: t_cq(min) + t_logic(min) ≥ t_hold + (t_skew_capture − t_skew_launch) + t_uncertainty_hold.
A faster clock shrinks T and only hurts setup. Hold has no T in it: frequency-independent,
which is why a hold bug can't be fixed by slowing the clock.

M2Q3 · A2. A path fails hold by 30 ps after CTS. List three fixes in the order backend would try them, and one fix an RTL engineer can make.

Gemini Answer

GPT Answer

Insert delay cells, downsize/use slower data-path cells, then adjust clock skew if feasible; actual order depends on the implementation flow. RTL can change the microarchitecture or move a register boundary, but adding combinational RTL delay is unreliable and not a normal hold fix.

Claude Answer

Backend order: (1) insert delay/hold-fix buffers on the data path, (2) swap to
slower or higher-Vt cells, (3) adjust clock tree skew (reduce early launch / late capture).
RTL side: avoid the pattern — zero-logic flop-to-flop paths across clock-gate or tree
boundaries, scan-shift paths between chains (lock-up latches), or data crossing between
different-edge or divided clocks without a register.

M2Q4 · A3. "Useful skew" — what is it, who applies it, and why is it dangerous for hold?

Gemini Answer

GPT Answer

Useful skew deliberately changes clock arrival times to redistribute slack. Delaying capture helps setup on that path but hurts its hold; it also changes adjacent paths' budgets. PD owns the physical implementation and checks all corners.

Claude Answer

Deliberately delaying the capture clock of a setup-failing endpoint so it borrows
time from the following stage. CTS/PD applies it. Danger: the borrowed stage launches
later, so its downstream setup gets tighter, and the same path's hold check gets worse
because the capture edge now arrives after the launch edge plus min delay.

M2Q5 · A4. What exactly is a multicycle path constraint telling STA? Why does a set_multicycle_path 2 almost always need a companion -hold constraint?

Gemini Answer

GPT Answer

Multicycle setup changes the intended launch/capture edge pairing. For ordinary same-clock N-cycle setup with original-edge hold, use setup N plus hold N-1. Different clock periods or -start/-end semantics require checking the actual edges, not applying this recipe blindly.

Claude Answer

set_multicycle_path N -setup tells STA the data launched at edge 0 is captured at
edge N, so the path has N periods. By default the hold check moves with it, to edge N−1,
demanding the data be held stable for N−1 cycles after launch — never what you mean.
set_multicycle_path N-1 -hold moves the hold check back to the launch edge.

M2Q6 · A5. Why might a multicycle path that is correct at the RTL hand-off become a silicon bug? Name two mechanisms.

Gemini Answer

  1. Missing enable qualification / early read: Downstream logic samples the destination register (or an intermediate node) after 1 cycle instead of waiting for the 2-cycle enable strobe.
  2. SDC pattern mismatch after synthesis: Ungrouping, register replication, or retiming renames the start/end flops so the set_multicycle_path wildcard partially misses (or the -hold rule is dropped during SoC SDC merge), causing PD to insert massive hold buffers or miss setup timing.

GPT Answer

An enable changes so a consumer uses data earlier than the exception allows; or integration drops/misapplies an exception after hierarchy changes. Wrong edge/hold pairing is another risk. Constraint errors may cause bad optimization or hide a violation; the exception itself does not change hardware.

Claude Answer

(1) The RTL stability assumption breaks: a new consumer samples the output early,
or the inputs are re-driven sooner than N cycles (back-to-back MU users). (2) The constraint decouples from the netlist: hierarchy ungroup, renaming, retiming or clock-gating insertion changes the start/end points, or the SDC merge at SoC drops it, so the path becomes unconstrained or mis-constrained. Plus the -hold mistake of A4.

M2Q7 · A6. False path vs. multicycle path vs. case analysis: give an example of each from a Wi-Fi MAC.

Gemini Answer

GPT Answer

False path: mutually exclusive functional/test modes, proven impossible in the analyzed mode. Multicycle: a launch/capture enable protocol that permits N cycles. Case analysis: pin scan/test mode low for functional STA. A slowly changing configuration register is not automatically a false path.

Claude Answer

False path: static config registers (MAC address, BSSID) to datapath, or scan-enable
into functional logic. Multicycle: a TBTT compare against a target register that updates
once per beacon interval. Case analysis: scan_mode = 0 and the test clock mux select
pinned to functional for the functional STA run.

M2Q8 · A7. At 1 GHz in a modern FinFET node, roughly how many levels of logic fit in a cycle? Walk me through your estimate (FO4 or gate delays, flop overhead, skew/uncertainty budget).

Gemini Answer

GPT Answer

Estimate using the actual library: 1 ns - flop overhead - uncertainty/skew - routing. For example, 200 ps overhead plus 150 ps wiring leaves 650 ps; at 25-40 ps per effective logic level that is roughly 16-26 simple levels. This is a planning estimate, not a FinFET guarantee.

Claude Answer

1 GHz = 1000 ps. Ask the library first. Typical 5 nm: clk-to-q ≈ 60–80 ps, setup ≈
30–50 ps, skew + jitter/uncertainty ≈ 80–120 ps, so roughly 750–800 ps of logic. FO4 ≈ 12–15
ps, but a real NAND2/NOR2 with FO3 and wire ≈ 25–35 ps. That is about 22–30 simple gate
levels, or in datapath terms: a 32-bit adder (~8–10 levels) plus a mux, not a multiplier.

M2Q9 · A8. What are path groups in PrimeTime, and why would you want reg-to-reg separated from in-to-reg when reading a first report?

Gemini Answer

GPT Answer

Path groups organize optimization/reporting by clocks or endpoint classes. Separate register/register from input/register so poor I/O budgets do not obscure internal critical paths.

Claude Answer

Path groups are the buckets PrimeTime reports worst paths in (per clock by default,
plus in2reg, reg2out, reg2reg if you create them). Input/output delays are often
guesses that dominate the first report; separating reg-to-reg lets you see the real
internal worst path and lets synthesis weight the groups separately.

M2Q10 · A9. Max transition / max capacitance violations: are they timing bugs? What do they mean for the RTL author?

Gemini Answer

GPT Answer

Transition/capacitance violations are electrical design-rule failures, and can invalidate delay assumptions or hurt power/reliability. Reduce fanout and mux load, localize control, or coordinate buffering/replication with PD.

Claude Answer

No, they are design-rule violations. Outside the characterized transition/cap range
the delay model is invalid, and slow edges hurt timing, noise and crowbar current. For the
RTL author they mean a high-fanout net or a huge mux: replicate the register, build a
fanout tree, or pipeline the enable (out_ready, resets, clock enables are usual suspects).

M2Q11 · A10. Register retiming in synthesis: what does it do, what does it break downstream (name at least LEC and DFT), and how do you contain the damage?

Gemini Answer

GPT Answer

Retiming moves registers across logic while preserving an allowed sequential behavior. It complicates register matching, resets, scan planning, and debug. Limit its scope and use an equivalence flow that understands the transformation; regenerate DFT artifacts if implementation changes.

Claude Answer

Retiming moves flops across combinational logic to balance stages. It breaks the
register correspondence LEC depends on (you need sequential equivalence or a retiming-aware
flow), changes which flops exist for scan chains and may give a moved flop a reset value
that can't be expressed, kills signal visibility for debug and ECO. Contain it: enable only
inside a specific arithmetic module with fixed boundary registers, no resets on the
retimed flops, retime once and freeze, keep a sequential-equivalence checkpoint.

M2Q12 · A11. Latency vs. throughput: a 5-stage pipeline with a 1-cycle bubble every 4 transfers — what is its throughput, and what does that cost in a system with fixed SIFS deadlines?

Gemini Answer

GPT Answer

One bubble per four transfers gives 4/5 transfer/cycle after fill. A five-stage pipeline adds about five cycles of latency, depending on convention. Account for bubbles, queuing, and dependencies in the complete RX-to-TX deadline; do not assume one SIFS value for every PHY.

Claude Answer

4 transfers per 5 cycles = 0.8 transfers/cycle, latency 5. SIFS (16 µs at 5/6 GHz)
is shared by PHY RX end, MAC response build and PHY TX preamble; a 20% throughput loss on
a per-byte or per-MPDU pipeline (crypto, FCS) scales with frame size and eats margin we
don't own. On a per-PPDU block it's noise.

M2Q13 · A12. You have a 32-bit × 16-bit multiply followed by a ceil-divide by a small variable integer. Describe how you would implement this without a divider and how many cycles it would take at a tight clock.

Gemini Answer

GPT Answer

Use a reciprocal table for supported divisors, a pipelined multiply, then an exact remainder correction. Bound approximation error to prove the correction count. Budget roughly 4-6 arithmetic cycles plus decode, subject to mapped timing; repeated subtraction has data-dependent worst-case latency.

Claude Answer

Multiply: 32×16 → 48 bits, two stages at a tight clock (hand-split the partial
products, or a library Booth/Wallace cell). Ceil-divide by a small-set variable d:
reciprocal ROM r = ceil(2^k/d) with k ≥ numerator width, q = ((n + d − 1) · r) >> k,
then one correction if (q·d > n + d − 1) q−1. Two stages for the reciprocal multiply,
one to two for the correction multiply, one for the compare: about 6 cycles total.
Alternative if latency is free: a radix-4 restoring divider, 2 bits/cycle, tiny.

M2Q14 · A13. How do you decide where to cut a datapath into stages? Name three signals/heuristics.

Gemini Answer

  1. Minimum cut-set width (bit-width bottleneck): Cut where the total number of bits crossing the boundary is smallest (e.g., after an adder tree reduction or encoder rather than across all partial products).
  2. Logic-depth symmetry (~15–20 FO4 levels): Cut right after heavy arithmetic blocks (multipliers, wide carry-propagate adders, SRAM outputs) and before high-fanout muxes.
  3. Control/handshake boundaries: Keep tightly coupled feedback loops inside a single stage so you don't introduce stall bubbles.

GPT Answer

Cut around multiplier/compressor trees, long carry/decode paths, and high-fanout control. Balance physical delay and register cost; carry all metadata/valid bits through the same cuts.

Claude Answer

Cut (1) where the bit width is smallest (fewest flops, cleanest valid), (2) after
each operator of comparable depth so stages balance, (3) before high-fanout decode or
large muxes, (4) so every stage reads only from the previous stage (no skip paths),
(5) never through a recurrence — a feedback loop can't be pipelined without changing the
algorithm. Then let the first synthesis report move the cuts.

M2Q15 · A14. When is a combinational output from a block acceptable at an IP boundary, and what do you document for the integrator?

Gemini Answer

GPT Answer

A combinational boundary is acceptable with an agreed input/output delay budget, no handshake loop, and documented load/fanout. Deliver SDC, latency, operating modes, and the cross-block timing contract.

Claude Answer

Acceptable when it is specified and budgeted: the IP's SDC carries set_input_delay
/ set_output_delay (or max_delay) for that path, the integration guide has a timing
budget table ("bb_ready is combinational from bb_valid, ≤ 300 ps"), and the protocol
allows it (AXI ready may depend combinationally on valid). Default is registered.

Part B — Deep dive: re-pipeline the Tx length-parameter datapath (0:20–0:55)

The Tx path must compute, per PPDU, the number of OFDM symbols and the padding/length
fields that go into the PHY preamble. A simplified version of the legacy block:

Inputs (valid for one cycle with tx_start):
  psdu_len_bytes[19:0]       // A-MPDU length
  mcs[3:0], nss[2:0], bw[2:0], ldpc, stbc, dcm, gi_ltf[1:0]
  n_users[2:0]               // MU: up to 8 users
  per-user: ru_size[3:0], mcs_u[3:0], nss_u[2:0]  (serially, one per cycle after tx_start)

Steps (legacy, combinational, constrained as a 3-cycle multicycle path):
  1. N_DBPS = lookup(mcs, nss, bw/ru_size, dcm)            // 1 of ~1500 table entries
  2. N_SYM_init = ceil( (8*psdu_len + 16 + 6*(~ldpc)) / N_DBPS )
  3. if stbc: N_SYM = 2*ceil(N_SYM_init/2)
  4. if ldpc: run the 802.11 LDPC encoding-parameter procedure:
       N_pld, N_avbits, N_cw, L_LDPC, N_shrt, N_punc, N_rep -> may add one extra symbol
  5. TXTIME = T_preamble(bw, nss, gi_ltf, n_users) + N_SYM * T_SYM(gi)
  6. For MU: N_SYM is the MAX over users of per-user N_SYM; each user then gets
     pre-FEC padding so all users finish at the same symbol.
  7. Output: n_sym, txtime_us, per-user pad bits, legacy L-SIG length =
     ceil((TXTIME - 20us)/4) * 3 - 3 - m   (where m is a per-PPDU constant)

Target: 640 MHz MAC clock, 5 nm. The 3-cycle multicycle path has caused two timing
escapes in the last generation because the PD team did not get the -hold side right.
Your job: remove it.

M2Q16 · B1. Clarify

  1. (5 min) Clarify. Ask the interviewer whatever you need: how often does a new PPDU
    arrive (latency budget)? Is the per-user loop allowed to serialize? Which outputs are
    needed first by the PHY?

Gemini Answer

GPT Answer

Ask for PPDU initiation interval, worst-case latency, first PHY-needed output, per-user arrival schedule, buffering/backpressure, supported rate matrix, and exact LDPC/rounding rules. Three-bit user/NSS fields need an explicit encoding for eight. Confirm whether outputs may be streamed or must retire atomically.

Claude Answer

1. Clarify (what I'd ask and the assumed answers)

M2Q17 · B2. Draw the pipeline

  1. (15 min) Draw the pipeline. Propose a stage-by-stage breakdown. For each stage name
    the arithmetic it contains and why you believe it closes at 640 MHz. Specifically address:
    • replacing the ceil-divide by a variable N_DBPS (hint: N_DBPS takes a small number of
      distinct values; or reciprocal-multiply; or iterative subtract — justify your choice),
    • the serial per-user loop for MU and the running MAX,
    • the LDPC extra-symbol decision, which depends on the result of step 2,
    • the L-SIG length formula, which depends on TXTIME.

Gemini Answer

Task 2: Stage-by-Stage Pipeline Breakdown (640 MHz, 1.56 ns period)
[S0: Input Latch & Factored N_DBPS Decode]
   - Register per-user (mcs_u, nss_u, ru_size, ldpc, stbc, dcm)
   - Lookup N_SD (12b), N_BPSCS*R numerator/denominator, and 36-bit Reciprocal R_NDBPS = ceil(2^36 / N_DBPS)
   - Compute num_bits = (psdu_len_bytes << 3) + 16 + (ldpc ? 0 : 6)   [24-bit adder]
        |
[S1: Reciprocal Multiply Stage 1 (Partial Products)]
   - Start 24-bit (num_bits) * 36-bit (R_NDBPS) -> Wallace tree reduction / Stage 1 of 2-stage pipelined mult
   - In parallel: finish factored N_DBPS[15:0] exact integer value
        |
[S2: Reciprocal Multiply Stage 2 & Initial N_SYM_init]
   - Complete 60-bit product; quotient estimate q = prod[59:36]
   - Exact ceil-divide adjustment: because R_NDBPS = ceil(2^36 / N_DBPS) and num_bits < 2^24,
     ceil(num_bits / N_DBPS) == ((num_bits - 1) * R_NDBPS) >> 36 + 1  (exact with zero remainder multiply!)
   - Apply STBC even-symbol rounding: n_sym_s2 = (stbc && q[0]) ? (q + 1) : q
        |
[S3: LDPC N_avbits & Extra-Symbol Threshold Check]
   - Compute N_avbits = N_DBPS * n_sym_s2  (16b x 12b mult)
   - Compare shortening/puncturing inequality: does N_punc exceed threshold -> ldpc_extra_sym (0 or 1, or 2 if STBC)
        |
[S4: Running MU Max & Final N_SYM]
   - n_sym_user = n_sym_s2 + (ldpc_extra_sym ? (stbc ? 2 : 1) : 0)
   - Update running max across users: max_n_sym <= (first_user || n_sym_user > max_n_sym) ? n_sym_user : max_n_sym
        |
[S5: TXTIME & L-SIG Length (Run once after last user finishes S4)]
   - txtime_us = T_preamble + max_n_sym * T_sym(gi)  (shift-add: T_sym is 13.6, 14.4, or 16.0 us in 0.4 us units)
   - l_sig_len = ceil((txtime_us - 20) / 4) * 3 - 3 - m  (shift by 2 + multiply by 3 via (x << 1) + x)

GPT Answer

Stage Work
S0 Capture packet context; assign PPDU/user IDs; validate configuration.
S1 Factored rate lookup, divisor/reciprocal selection, 24-bit numerator 8*len+16+tail.
S2-S3 Reciprocal multiply with a real internal pipeline cut if required.
S4 Multiply trial quotient by divisor.
S5 Exact floor correction, then ceiling; STBC rounding.
S6-S8 LDPC capacity/codeword arithmetic and exact extra-symbol decision; pipeline products and comparisons.
S9 Update running maximum on completed user results; store per-user information.
S10-S11 After last user completes, calculate common duration and L-SIG fields.
Padding pass Derive each user's final padding from the common symbol count and coding rules.

The stage count is a proposal, not proof of 640 MHz closure. LDPC common-duration selection may require another bounded adjustment pass; verify the standard's exact dependency rather than assuming independent per-user rounding always suffices.

Accept one user per cycle if resources support that initiation interval. The last serial user adds U-1 cycles; tagging and PPDU-level state prevent a late result from contaminating a new packet. Convert times to integer fine units, preserve fractional symbol duration, and apply each specified ceiling at the correct point. For L-SIG, implement ceiling division by 4 only after consistent unit conversion; guard subtraction and field overflow.

Claude Answer

2. Pipeline (all stages registered, a valid bit travels alongside)
Stage Contents Why it closes at 640 MHz (1.56 ns)
S0 Register inputs. Factored N_DBPS: N_SD(ru/bw,dcm) × N_BPSCS(mcs) × nss × R(mcs); same index selects recip = ceil(2^25 / N_DBPS) from a small ROM Two small ROMs + one small multiply; the factored form is what replaced the 1500-entry case in my redesign
S1 num = {psdu_len,3'b0} + 16 + (ldpc ? 0 : 6); num_c = num + N_DBPS − 1 (turns ceil into floor) Two adders ≤ 25 bits
S2 Hand-split partial products: num_c × recip[11:0], num_c × recip[22:12] Each a 25×12 multiplier, ~25 gate levels
S3 Sum partials; q_est = prod[25 +: 22] One 48-bit add
S4 q_est × N_DBPS (22×19) Borderline; see plan B
S5 n_sym_init = (q_est·d > num_c) ? q_est − 1 : q_est Compare + decrement
S6 STBC: n_sym = stbc ? n_sym_init + n_sym_init[0] : n_sym_init; LDPC: N_pld = n_sym_init × N_DBPS, N_avbits = N_CBPS × n_sym (two small multiplies, reuse S4-style split if needed) Multiplies by values already in registers
S7–S8 LDPC: pick L_LDPC by N_avbits range, N_cw, N_shrt, N_punc, the two punctuate/repeat tests → extra_sym; n_sym += extra_sym (×2 if stbc) Compares and shifts; the divides in the spec are by constants (648/1296/1944) → constant-reciprocal multiplies
S9 TXTIME = T_pre(bw,nss,gi_ltf,n_users) + n_sym × T_SYM(gi) in 0.1 µs units (136/144/160 → shift-adds selected by gi) Constant multiplies
S10 L-SIG: ceil((TXTIME − 20)/4)·3 − 3 − m → shift, round, shift-add Trivial

MU: per-user tuples stream through S0–S5 one per cycle; a running-MAX register collects
n_sym across users (the AP picks the max). After the last user, the common n_sym goes
through S6–S10 once, and the stored per-user N_DBPS_u stream through a second S4-style
multiply to produce pad_bits_u = n_sym × N_DBPS_u − bits_u (pre-FEC padding so every user
ends on the same symbol).

Why reciprocal-multiply over the alternatives: with k = 25 ≥ width(num_c) and
r = ceil(2^k/d), the estimate is floor(num_c/d) or one too big, never too small, so one
compare fixes it. Iterative subtract (radix-4, 12 cycles, ~300 gates) is smaller and I'd
pick it if the distinct-N_DBPS count makes the ROM big; it just can't stream MU users at
one per cycle. Dividing by each factor in turn (ceil(ceil(x/a)/b) = ceil(x/ab)) kills the
ROM but needs four divide stages — too much for the win.

M2Q18 · B3. Code one stage

  1. (10 min) Code one stage. Write the SystemVerilog for the stage containing the
    ceil-divide, including its valid pipeline and any constant tables. Be explicit about
    widths.

Gemini Answer

Task 3: Live Code — Stage S1/S2 Exact Reciprocal Ceil-Divide (SystemVerilog)
// Exact ceil(num_bits / n_dbps) for num_bits in [1 .. (5_484_000 * 8 + 22)] (< 2^26)
// identity: ceil(A / B) = floor((A - 1) / B) + 1  (for A >= 1)
// Choosing K = 36: with R = ceil(2^36 / B), floor(((A - 1) * R) / 2^36) + 1 == ceil(A / B)
// holds identically for all A < 2^26 and B < 2^16 because the maximum over-approximation
// error is (A - 1) * (1 - 1/B) < 2^26 < 2^36 / B.

module tx_nsym_div_stage (
  input  logic        clk,
  input  logic        rst_n,
  input  logic        in_valid,
  input  logic        in_stbc,
  input  logic [25:0] in_num_bits,   // 8 * psdu_len + 16 + 6*(~ldpc), >= 16
  input  logic [35:0] in_recip_ndbps,// ceil(2^36 / N_DBPS) from factored LUT
  output logic        out_valid,
  output logic [14:0] out_n_sym_init
);

  // Stage 1: prepare (A - 1) and register inputs to multiplier
  logic        s1_valid, s1_stbc;
  logic [25:0] s1_num_m1;
  logic [35:0] s1_recip;

  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) s1_valid <= 1'b0;
    else        s1_valid <= in_valid;
  end

  always_ff @(posedge clk) begin
    if (in_valid) begin
      s1_stbc   <= in_stbc;
      s1_num_m1 <= in_num_bits - 26'd1;
      s1_recip  <= in_recip_ndbps;
    end
  end

  // Stage 2: 26x36 multiply (synthesis maps/retimes across s2_prod_q if needed)
  logic        s2_valid, s2_stbc;
  logic [61:0] s2_prod;

  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) s2_valid <= 1'b0;
    else        s2_valid <= s1_valid;
  end

  always_ff @(posedge clk) begin
    if (s1_valid) begin
      s2_stbc <= s1_stbc;
      s2_prod <= s1_num_m1 * s1_recip;
    end
  end

  // Stage 3: shift right by 36, add 1, and round up to even if STBC
  logic [14:0] q_raw, q_stbc;
  assign q_raw  = s2_prod[50:36] + 15'd1;
  assign q_stbc = (s2_stbc && q_raw[0]) ? (q_raw + 15'd1) : q_raw;

  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) out_valid <= 1'b0;
    else        out_valid <= s2_valid;
  end

  always_ff @(posedge clk) begin
    if (s2_valid) out_n_sym_init <= q_stbc;
  end

endmodule

GPT Answer

3. Exact ceil-divide example

Below is a complete arithmetic unit for a parameterized set of positive divisors. Default entries are illustrative, not the full Wi-Fi table. Generate D from the approved legal-rate reference. Numerator is 24 bits, divisor is 19 bits because the exercise's full rate range exceeds 16 bits. It accepts a new input each cycle; there is no output backpressure.

Let R=floor(2^24/D) and q0=floor(x*R/2^24). Since x<2^24, q0 is the exact floor quotient or one below it. Correct the floor first, then add one for a nonzero remainder. Merely incrementing q0 once when its product is below x does not always implement ceiling.

module ceil_div_set #(
  parameter int ND = 3,
  parameter int IDW = (ND > 1 ? $clog2(ND) : 1),
  parameter logic [18:0] D [ND] = '{19'd12,19'd24,19'd36}
) (
  input logic clk, rst_n, in_valid,
  input logic [23:0] x,
  input logic [IDW-1:0] d_id,
  output logic out_valid,
  output logic [24:0] y
);
  wire [24:0] recip [ND];
  for (genvar g=0; g<ND; g++) begin : g_recip
    // Elaboration-time division only. Contract: every D[g] > 0.
    assign recip[g] = 25'd16777216 / D[g];
  end
  logic [3:0] v;
  logic [48:0] product_q;
  logic [23:0] x1, x2, x3, q2, floor3;
  logic [18:0] d1, d2;
  logic [42:0] trial_product, p2, floor_product3;
  logic [24:0] next_q;
  always_comb begin
    trial_product = 43'(product_q[47:24]) * 43'(d1);
    next_q = {1'b0,q2} + 25'd1;
  end
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) v <= '0;
    else v <= {v[2:0], in_valid && (int'(d_id) < ND)};
  end
  always_ff @(posedge clk) begin
    if (in_valid && (int'(d_id) < ND)) begin
      product_q <= 49'(x) * 49'(recip[d_id]);
      x1 <= x;
      d1 <= D[d_id];
    end
    if (v[0]) begin
      q2 <= product_q[47:24];
      p2 <= trial_product;
      x2 <= x1;
      d2 <= d1;
    end
    if (v[1]) begin
      if (p2 + 43'(d2) <= 43'(x2)) begin
        floor3 <= next_q[23:0];
        floor_product3 <= p2 + 43'(d2);
      end else begin
        floor3 <= q2;
        floor_product3 <= p2;
      end
      x3 <= x2;
    end
    if (v[2]) y <= {1'b0,floor3} + 25'(floor_product3 != 43'(x3));
  end
  assign out_valid = v[3];
endmodule

This code specifies four registered arithmetic steps; assigning a multiply to one register does not automatically pipeline its internal logic. If timing fails, split the multiplier itself and extend valid/metadata latency. HDL compilation is unverified in this environment.

Claude Answer

// q = ceil(num / n_dbps) via reciprocal multiply and one correction.
// Preconditions: num < 2^NUM_W, 6 <= n_dbps < 2^DIV_W,
//                recip == ceil(2^K / n_dbps) with K >= NUM_W+1.
// Then q_est = floor(num_c * recip / 2^K) is exact or one too large, never too small.
module ceil_div_stage #(
  parameter int NUM_W = 24,
  parameter int DIV_W = 19,
  parameter int K     = 25,
  parameter int RCP_W = 23,            // ceil(2^25 / 6) needs 23 bits
  parameter int Q_W   = 22             // 2^24 / 6 < 2^22
)(
  input  logic             clk, rst_n,
  input  logic             in_valid,
  input  logic [NUM_W-1:0] num,        // 8*psdu_len + 16 + 6*~ldpc
  input  logic [DIV_W-1:0] n_dbps,
  input  logic [RCP_W-1:0] recip,      // from the S0 ROM
  output logic             out_valid,
  output logic [Q_W-1:0]   q
);
  localparam int NC_W = NUM_W + 1;     // num + n_dbps - 1
  localparam int RL   = RCP_W / 2;     // low half of recip
  localparam int RH   = RCP_W - RL;
  localparam int P_W  = NC_W + RCP_W;

  // valid pipeline: the only reset flops in the stage
  logic [5:1] v;
  always_ff @(posedge clk or negedge rst_n)
    if (!rst_n) v <= '0;
    else        v <= {v[4:1], in_valid};
  assign out_valid = v[5];

  // datapath registers, reset-less (qualified by v[])
  logic [NC_W-1:0]      nc1, nc2, nc3, nc4;
  logic [DIV_W-1:0]     d1, d2, d3;
  logic [RCP_W-1:0]     r1;
  logic [NC_W+RL-1:0]   pl2;           // num_c * recip[RL-1:0]
  logic [NC_W+RH-1:0]   ph2;           // num_c * recip[RCP_W-1:RL]
  logic [P_W-1:0]       prod3;
  logic [Q_W-1:0]       qe3, qe4;
  logic [Q_W+DIV_W-1:0] qd4;

  assign prod3 = P_W'(pl2) + (P_W'(ph2) << RL);

  always_ff @(posedge clk) begin
    // P1: ceil -> floor
    nc1 <= NC_W'(num) + NC_W'(n_dbps) - 1'b1;
    d1  <= n_dbps;
    r1  <= recip;
    // P2: hand-split multiplier (two half-width products)
    pl2 <= nc1 * r1[RL-1:0];
    ph2 <= nc1 * r1[RCP_W-1:RL];
    nc2 <= nc1;  d2 <= d1;
    // P3: combine, take the integer part
    qe3 <= prod3[K +: Q_W];
    nc3 <= nc2;  d3 <= d2;
    // P4: back-multiply for the correction
    qd4 <= qe3 * d3;
    qe4 <= qe3;  nc4 <= nc3;
    // P5: estimate is exact or +1; never low
    q   <= (qd4 > (Q_W+DIV_W)'(nc4)) ? qe4 - 1'b1 : qe4;
  end
endmodule

Width notes: num_c < 2^24 + 2^19 < 2^25, so K = 25 gives
num_c·(r − 2^K/d)/2^K < 1, which is the "at most one too big" guarantee.

M2Q19 · B4. Defend it

  1. (5 min) Defend it.
    • What is the latency in cycles from tx_start to txtime valid? Is it within SIFS
      budget? (Interviewer will give you the number if you ask.)
    • Which stage would you bet fails timing first after place-and-route, and what is plan B?
    • How does this design get verified against the legacy combinational version? What would
      you keep from the old testbench?

Gemini Answer

GPT Answer

Claude Answer

Part C — Your questions (0:55–1:00)

M2Q20 · Questions for the interviewer

Gemini Answer

  1. "What is the synthesis clock-uncertainty / over-constraint margin target at RTL hand-off before physical design takes over?"
  2. "How does your team manage SDC ownership—do RTL designers write and maintain block-level .sdc files directly in git alongside the RTL?"
  3. "How early in the project do RTL owners get post-placement trial timing reports back from Innovus/Fusion Compiler?"

GPT Answer

Who owns SDC exceptions? When are post-place timing reports available to RTL? What latency/frequency margin is expected at handoff?

Claude Answer

  1. How early do RTL engineers see post-place timing, and is there an RTL hand-off margin
    policy (close at +10% over target)?
  2. Who owns the SDC through SoC integration, and how are IP-level exceptions reviewed?
  3. Is retiming allowed anywhere in the flow today, and how is LEC run on those blocks?

Additional notes

Notes. Material not tied to a question

Gemini Answer

No answer in gemini_answer.md.

GPT Answer

Practice answers; proposed cycle counts and architectures are estimates, not additional resume claims.

Claude Answer

No answer in claude_answer.md.