RTL Review

← 11 AMBA AXI and On-Chip Interconnect | Index | 13 DFT, Scan, MBIST and RTL Signoff →

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

Contents

0. Resume probe

M12Q1 · "Where did SRAM macros sit in your Wi-Fi MAC or neural network accelerator (beacon templates, TX/RX FIFOs, BA scoreboards, weight buffers), and what kind of macro was each?"

Gemini Answer

GPT Answer

"My Wi-Fi MAC ownership includes beaconing and datapaths, and my UCLA accelerator used ternary weights and folding. The resume does not specify SRAM macro types, capacities or wrappers. I would identify the actual macro/datasheet before claiming a particular memory integration. The following is a proposed wrapper design."

Claude Answer

Template (fill in the real macros):

"In the MAC: Tx/Rx payload FIFOs and aggregation buffers as 1R1W pseudo-dual-port macros,
because one side is a stream that can't stall and the other is DMA; beacon/frame templates
as single-port SRAM since firmware writes rarely and hardware reads once per beacon; BA
scoreboards and per-TID state as register files or flop arrays because they need
read-modify-write every MPDU and are small. In the NN accelerator the ternary weight
buffer was a single-port SRAM read in a fixed sequence with weights packed five trits per
byte, and the activations lived in a 1R1W buffer so the next layer's reads overlapped the
current layer's writes. The rule I carried out of both: flops under ~1–2 Kbit, a compiled
macro above, and never a combinational cone on CEN."

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

M12Q2 · A1. Compare a flip-flop array, a compiled Register File (1R1W RF), a Single-Port SRAM (1RW), a Pseudo-Dual-Port SRAM (1R1W two-port), and a True Dual-Port SRAM (2RW): rank them by area per bit and explain roughly where the bit-count crossover is between flops and a compiled macro.

Gemini Answer

GPT Answer

Dense 1RW SRAM usually has the lowest area/bit at substantial capacity, then additional-port SRAM/RF structures, with flops generally most expensive. 1R1W RF versus SRAM and 2RW ordering depend on compiler/size/port requirements; no universal rank or crossover bit count exists. Compare actual compiled area, periphery, latency and required banking.

Claude Answer

Smallest to largest per bit: 1RW single-port < 1R1W pseudo-dual-port (~1.3–1.5×) <
1R1W register file < 2RW true dual-port (~2×) < flip-flops (~8–15×). Crossover to a macro is
around 1–2 Kbit (32×32 to 64×32), where the decoder, sense amps, MBIST collar and placement
halo stop dominating.

M12Q3 · A2. Why is CLK → DOUT on a compiled SRAM so much slower than a standard-cell flip-flop, and what rule should an RTL designer follow on the CEN/WEN/ADDR inputs and DOUT outputs?

Gemini Answer

GPT Answer

SRAM reads include decode, wordline, bitline discharge and sensing, unlike a flop output arc. Keep address/CEN/WEN paths short and controlled, and capture DOUT locally before substantial logic. Whether inputs/outputs require explicit flops is a datasheet/timing decision, not a blanket language rule.

Claude Answer

The read is a small bitcell discharging a long bitline into a sense amp on a
self-timed internal clock: hundreds of ps, not a flop's 50 ps. Rule: drive CEN, WEN,
ADDR, DIN straight from flops with minimal logic, and capture DOUT in a flop with
nothing heavy in front of it.

M12Q4 · A3. You put a compiled SRAM inside a valid/ready pipeline. On cycle T, CEN=0 (read issued). On cycle T+1, DOUT appears on the SRAM pins, but the downstream out_ready drops to 0. Why can you not simply hold CEN=1 and expect DOUT to stay valid, or leave DOUT unbuffered?

Gemini Answer

GPT Answer

Disabling a later access cannot cancel a read already in flight, and the specified macro does not guarantee a held DOUT. Reserve response space before issuing and capture every returning word even if the sink just stalled.

Claude Answer

DOUT is only valid the cycle after a read; the macro doesn't hold it (next access,
precharge or sleep destroys it), and the read launched at T is already coming out at T+1 when
out_ready drops. So the data must land in a skid register while new launches stop, and
DOUT must never be the thing that waits.

M12Q5 · A4. What happens in a 1R1W (two-port) SRAM when the read port and write port access the exact same address in the same clock cycle? How does the RTL designer prevent X-propagation in simulation and corruption in silicon?

Gemini Answer

GPT Answer

Same-address read/write may return old/new/unknown data or violate macro restrictions. Follow the compiler's truth table. Use arbitration, explicit forwarding with aligned valid/address, or prohibit the collision. Do not depend on a simulation model's convenient behavior.

Claude Answer

Both wordlines fire on the same bitcell: read returns X/garbage and can disturb the
write. RTL detects rd_en && wr_en && raddr == waddr, suppresses the SRAM read, and forwards
registered wdata (write-through) or returns the old value for read-first semantics, with
an SVA that the macro never sees the collision.

M12Q6 · A5. Byte-write mask (BWEN / WMASK) vs. bit-write mask: if a memory macro only supports byte-write enables ([7:0] for 64-bit width) and you need to update a single 4-bit field, how do you design the Read-Modify-Write (RMW) pipeline and what hazard does back-to-back updates to the same address create?

Gemini Answer

GPT Answer

Read the old ECC/data word, merge the selected nibble while preserving its neighbor, then write the byte/codeword. Serialize or forward overlapping RMW operations by address. Back-to-back same-word updates otherwise lose the earlier modification.

Claude Answer

Two-stage RMW: read the word, then merge the 4-bit field and write back with the byte
enable. Back-to-back updates to the same address are a RAW hazard: the second read sees the
stale word before the first write lands. Fix with a bypass mux forwarding stage 1's merged
data into stage 0 (and a one-deep compare), or stall.

M12Q7 · A6. Why split one 4096×64 SRAM into four 1024×64 banks instead of using a single macro? Give one dynamic power reason, one floorplan/timing reason, and one bandwidth reason.

Gemini Answer

  1. Dynamic Power (~60% lower): Each read/write only precharges and discharges bitlines that are 1/4 as tall (1024 cells per bitline instead of 4096), and the other 3 idle banks stay unselected (CEN_N = 1).
  2. Timing & Floorplan: Shorter bitlines reduce T_ck_q by ~100–150 ps, and four smaller macros can be placed along the perimeter of the floorplan without blocking global routing channels.
  3. Bandwidth (up to 4×): Allows simultaneous read and write (e.g., 1R1W emulation using 1RW macros) whenever requests target different banks.

GPT Answer

Banking can reduce switched wordline/bitline capacitance, place smaller macros near clients and permit concurrent accesses to different banks. It adds periphery/mux/control and conflicts; neither area nor aggregate energy savings are automatic.

Claude Answer

Power: only one quarter-size array toggles per access. Timing/floorplan: shorter
bitlines and wordlines give a faster T_ck_q, and small macros fit between datapath
channels. Bandwidth: up to four concurrent accesses when addresses fall in different banks.

M12Q8 · A7. What are the EMA / RM (Extra Margin Adjustment / Read Margin) pins on an SRAM macro? Who sets their values, why can they change post-silicon, and how should they be wired in RTL?

Gemini Answer

GPT Answer

RM/EMA tune internal memory timing/margin, as defined by the vendor. Foundry/memory/implementation owners qualify settings; trim/register overrides may support post-silicon calibration. Wire approved constants or stable controlled configuration and include test overrides; never leave them floating or change them during active access.

Claude Answer

Margin pins that tune the sense-amp timing and wordline pulse against process
variation. Set by the memory compiler defaults, overridable from a quasi-static fuse/CSR bus
so bring-up can widen margin on a weak lot. In RTL: wire from the top-level static control
through the wrapper, never from logic, never changed while the macro is active.

M12Q9 · A8. Describe the three low-power modes of a modern SRAM macro: Light Sleep (LS), Deep Sleep (DS), and Shut Down (SD). Which ones retain data, and what is the wakeup latency rule before you can assert CEN=0?

Gemini Answer

GPT Answer

LS/DS/SD names and retention are vendor-specific. LS often retains; deeper modes may or may not retain, while shutdown commonly loses contents. Wait the specified wake-up interval with access disabled and reinitialize invalid contents before use. Do not assume every mode wakes in one cycle.

Claude Answer

Light sleep: periphery biased, data retained, ~1 cycle wake. Deep sleep: periphery
gated plus array source bias, retained, several cycles wake. Shut down: array power off,
data lost, long wake with inrush sequencing. Rule: deassert the sleep pin and wait the
datasheet's wake cycles with CEN=1 before the first CEN=0.

M12Q10 · A9. Why does an SRAM wrapper include an isolation clamp or qualifier on CEN during sleep/shut down transitions, and what happens if CEN glitches low while DS is asserted?

Gemini Answer

GPT Answer

Clamp access controls to their inactive polarity throughout entry/sleep/wake, with glitch-free sequencing. A low CEN during DS may violate the macro specification and cause corruption or unpredictable outputs; qualify returned valid state too.

Claude Answer

CEN low during a sleep transition violates the macro's DRC: internal clock fires
with the periphery unpowered, which can corrupt the array or return garbage, and simulation
models output X for everything. The wrapper qualifies CEN with the sleep state so it can't
happen, glitch or not.

M12Q11 · A10. ECC vs. parity on SRAMs: when do you use single-bit parity vs. SECDED ECC (e.g., 64-bit data + 8-bit Hamming code)? Why does SECDED interact badly with sub-word byte writes?

Gemini Answer

GPT Answer

Parity detects an odd number of flipped bits; SECDED corrects one and detects two within its guaranteed model. Use according to reliability/recovery requirements. A partial write changes ECC for the whole protected codeword, so requires an RMW or specialized per-byte ECC/mask scheme.

Claude Answer

Parity for data that can be refilled or dropped (caches, templates, payloads).
SECDED for state with no backup (descriptors, scoreboards, control tables). SECDED over a
64-bit word breaks sub-word writes because the new 8-bit code needs all 64 bits, forcing
RMW, or per-byte codes at higher overhead.

M12Q12 · A11. If an SRAM with SECDED ECC detects a correctable 1-bit error on a read, what should the wrapper do besides correcting the data sent to the datapath?

Gemini Answer

1.Combinational syndrome decode flips the bad bit so the downstream datapath receives clean 64-bit data with zero glitch.
2. Latch the failing raddr and syndrome into an ECC Error Address/Syndrome CSR, increment a saturating ecc_corr_err_cnt, and fire a maskable maintenance interrupt.
3. Schedule an opportunistic hardware scrub write-back of the corrected 72-bit word to that address when the SRAM bank is next idle so a second cosmic-ray bit flip on that same word doesn't turn into an uncorrectable 2-bit fatal error!

GPT Answer

Report/count the corrected error and address, and arrange a hazard-safe scrub/writeback so the persistent fault does not combine with a later fault. Coordinate scrub with functional writes and report uncorrectable errors separately.

Claude Answer

Log the address and syndrome to a status CSR, count correctable errors, raise a
threshold interrupt, and scrub: write the corrected word back during an idle cycle so a
second flip doesn't become uncorrectable.

M12Q13 · A12. In your UCLA Hardware Neural Network Accelerator (ternary weights) or Wi-Fi MAC tables, how do you pack non-power-of-two data widths (e.g., 1.6-bit/2-bit ternary weights or 48-bit MAC entries) into standard SRAM aspect ratios efficiently?

Gemini Answer

GPT Answer

Two-bit ternary encoding is simple; log2(3)~1.585 bits/weight is an information limit, not a directly addressable scalar width. Pack weights in vectors matched to access bandwidth; denser grouped ternary encoding costs decode logic. Pack 48-bit entries across words only if unaligned read/update/ECC costs justify the saved bits. The resume does not establish which packing I used.

Claude Answer

Pack to the word, not the entry: 5 trits in 8 bits (3⁵ = 243 ≤ 256) gives 40 trits
per 64-bit word; 48-bit MAC entries go four per three words with a 2-cycle or 2-bank
straddle, or better, compile a 48-wide macro — compilers take arbitrary widths and column
mux ratios, so pick the aspect ratio before packing.

M12Q14 · A13. Why do synthesis and STA engineers hate it when you drive an SRAM's CEN directly from a complex combinational decode expression?

Gemini Answer

GPT Answer

Deep decode creates address/control setup delay, fanout and possible switching glitches. Register/localize bank selects and access controls, budgeting the added latency. STA must use the real macro arcs and modes.

Claude Answer

CEN gates the macro's internal clock generator, so it has the tightest setup on
the macro and the worst slew sensitivity; a deep decode cone in front of it is the first
path to fail after placement and the hardest to fix because the macro can't move.

M12Q15 · A14. What ports does an SRAM wrapper expose to the DFT / MBIST controller, and why should functional RTL sit outside the MBIST wrapper rather than inside it?

Gemini Answer

GPT Answer

Expose test ownership/mode, address, write/read data, masks, enables, clocks/resets and status, plus repair/fuse/margin controls where required. Keep functional arbitration outside a standardized MBIST boundary so test can independently control/observe every macro operation. Honor existing wrapper architecture rather than assuming one universal port list.

Claude Answer

bist_en/test mode, bist_cen, bist_wen, bist_addr, bist_din, bist_dout,
repair/BISR chain, and the margin pins. Functional RTL stays outside so every wrapper on the
chip is identical, the MBIST controller is generated uniformly, and LEC can black-box the
raw macro cleanly.

Part B — Deep dive: 1R1W Emulation using Single-Port (1RW) SRAM Banks + Read Skid Wrapper (0:20–0:55)

A packet/aggregation buffer needs 4096 entries × 64 bits (32 KB) at 640 MHz with a peak
requirement of 1 write and 1 read per cycle (1R1W).

Traffic constraint from the MAC architecture:

M12Q16 · B1. (10 min) Bank Mapping and Conflict Arbitration

  1. (10 min) Bank Mapping & Conflict Arbitration.
    • How do you map addr[11:0] to (bank_sel[1:0], row_addr[9:0]) — low-order interleaving
      (addr[1:0]) or high-order banking (addr[11:10])? Justify based on sequential write vs.
      burst/random read patterns.
    • Since writes cannot be stalled, what happens when a read requests the same bank as a
      write in the same cycle? How about when rd_addr == wr_addr in the same cycle?
    • Adding a tiny 4-entry flop cache / write-buffer completely eliminates read stalls under
      sequential writes — explain how, or explain the simpler rd_ready stall scheme and its
      throughput bound.

Gemini Answer

GPT Answer

Use low-order interleaving: bank=addr[1:0], row=addr[11:2]. Sequential writes rotate banks, distributing activity and leaving each bank free three of four write cycles. High-order banking pins sequential writes to one bank for long runs.

Writes have priority because there is no write-ready. Stall a conflicting read by keeping rd_ready=0; nonconflicting reads may proceed if response capacity exists. For equal read/write addresses, a defined write-through forwarding path can serve the read with incoming data, if that is the specified ordering. Same bank/different row cannot be solved by that forwarding.

A four-entry recent-write cache does not eliminate conflicts for arbitrary reads: a read can target an uncached row in the currently written bank. The simple scheme gives about 75% conflict-free service for independent uniformly random reads with continuous writes, before response stalls; that is not a deterministic throughput guarantee. A fixed pending address encounters at most one write conflict in four sequential write cycles when awake and downstream space is available. Adversarial changing offered addresses can conflict every cycle. More guaranteed bandwidth needs replication, buffering with a proven schedule, faster internal access, or a stronger traffic contract.

Claude Answer

M12Q17 · B2. (15 min) Live Coding — SRAM Read-to-Valid/Ready Skid Wrapper

  1. (15 min) Live Coding — SRAM Read-to-Valid/Ready Skid Wrapper.
    Write the synthesizable SystemVerilog for a 1-cycle-latency SRAM read wrapper that bridges
    the raw SRAM read launch (mem_cen_n, mem_addr, mem_dout) into a standard
    rresp_valid/rresp_ready/rresp_data interface with zero read loss under arbitrary
    downstream backpressure
    and full 1-read-per-cycle throughput.
    (Hint: when mem_cen_n == 0 on cycle T, the data arriving on mem_dout in cycle T+1
    is already in flight — where must it go if rresp_ready is 0 on cycle T+1?)

Gemini Answer

// Bridges a 1-cycle-latency synchronous SRAM read interface into a standard
// AXI/valid-ready downstream pipeline with:
//   - Registered rd_ready (no combinational path from rresp_ready to SRAM CEN_N)
//   - Full 1-read/cycle throughput when rresp_ready == 1
//   - Zero read data loss under arbitrary rresp_ready backpressure
module sram_read_skid_wrapper #(
  parameter int ADDR_W = 12,
  parameter int DATA_W = 64
) (
  input  logic              clk,
  input  logic              rst_n,

  // Upstream read request
  input  logic              rd_valid,
  output logic              rd_ready,
  input  logic [ADDR_W-1:0] rd_addr,
  input  logic              bank_conflict, // 1 if write owns the target bank this cycle

  // To/From 1-cycle latency SRAM (DOUT valid 1 cycle after mem_rd_en)
  output logic              mem_rd_en,
  output logic [ADDR_W-1:0] mem_rd_addr,
  input  logic [DATA_W-1:0] mem_dout,

  // Downstream valid/ready read response
  output logic              rresp_valid,
  input  logic              rresp_ready,
  output logic [DATA_W-1:0] rresp_data
);

  // Track whether a read launched on cycle T-1 is emerging on mem_dout this cycle (T)
  logic              rd_inflight_q;

  // Two storage registers on the output side:
  //   1. out_data_q  (main registered output driving rresp_data)
  //   2. skid_data_q (overflow register when out_data_q is stalled AND rd_inflight_q arrives)
  logic [DATA_W-1:0] out_data_q,  skid_data_q;
  logic              out_valid_q, skid_valid_q;

  // How many items are currently stored or in-flight?
  // If skid_valid_q == 1 (2 items stored) OR (out_valid_q == 1 && rd_inflight_q == 1)
  // (1 stored + 1 arriving), we have 2 items committed and cannot launch another read
  // unless rresp_ready is popping right now. To keep mem_rd_en free of rresp_ready:
  // Conservative registered ready: launch whenever < 2 slots are committed, i.e.,
  // !skid_valid_q && !(out_valid_q && rd_inflight_q && !rresp_ready)
  wire pop        = out_valid_q && rresp_ready;
  wire can_launch = !skid_valid_q && (!out_valid_q || !rd_inflight_q || rresp_ready);

  assign rd_ready    = can_launch && !bank_conflict;
  assign mem_rd_en   = rd_valid && rd_ready;
  assign mem_rd_addr = rd_addr;

  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      rd_inflight_q <= 1'b0;
      out_valid_q   <= 1'b0;
      skid_valid_q  <= 1'b0;
    end else begin
      rd_inflight_q <= mem_rd_en;

      // Update out_valid_q
      if (skid_valid_q) begin
        out_valid_q <= 1'b1; // Skid drains into out_data_q on pop
      end else if (rd_inflight_q) begin
        out_valid_q <= 1'b1; // Arriving SRAM read lands in out_data_q
      end else if (pop) begin
        out_valid_q <= 1'b0;
      end

      // Update skid_valid_q: fills when SRAM read arrives while out_valid_q is stalled
      if (skid_valid_q && pop) begin
        skid_valid_q <= 1'b0; // Drained into out_data_q
      end else if (rd_inflight_q && out_valid_q && !rresp_ready) begin
        skid_valid_q <= 1'b1;
      end
    end
  end

  // Datapath capture registers (mem_dout goes straight into flops!)
  always_ff @(posedge clk) begin
    if (rd_inflight_q && out_valid_q && !rresp_ready) begin
      skid_data_q <= mem_dout;
    end

    if (skid_valid_q && pop) begin
      out_data_q <= skid_data_q;
    end else if (rd_inflight_q && (!out_valid_q || rresp_ready)) begin
      out_data_q <= mem_dout;
    end
  end

  assign rresp_valid = out_valid_q;
  assign rresp_data  = out_data_q;

endmodule

GPT Answer

Reserve capacity for both returned words and the unreturned read. This core has a two-word response FIFO plus one-cycle pending state; the issue rule ensures their combined occupancy never exceeds two. read_allowed represents bank arbitration and awake/wake-qualified access. Only accepted requests drive the macro. Reset must quiesce/discard outstanding macro results.

Timing convention: a read accepted at edge T produces DOUT stable for capture at edge T+1. If the macro instead specifies DOUT only after T+1, add an extra pending stage/capture edge and increase reserved capacity accordingly; confirm setup using its timing model.

module sram_read_wrap #(
  parameter int AW=10, W=64
) (
  input logic clk, rst_n,
  input logic rd_valid, read_allowed,
  output logic rd_ready,
  input logic [AW-1:0] rd_addr,
  output logic mem_cen_n,
  output logic [AW-1:0] mem_addr,
  input logic [W-1:0] mem_dout,
  output logic rresp_valid,
  input logic rresp_ready,
  output logic [W-1:0] rresp_data
);
  logic [W-1:0] data_q [2];
  logic rptr_q, wptr_q, pending_q;
  logic [1:0] count_q;
  logic [2:0] reserved_after_pop;
  logic issue, pop;
  assign rresp_valid = (count_q != 0);
  assign rresp_data = data_q[rptr_q];
  assign pop = rresp_valid && rresp_ready;
  assign reserved_after_pop = {1'b0,count_q} + 3'(pending_q) - 3'(pop);
  assign rd_ready = rst_n && read_allowed && (reserved_after_pop < 3'd2);
  assign issue = rd_valid && rd_ready;
  assign mem_cen_n = !issue;
  assign mem_addr = rd_addr;
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      rptr_q <= 1'b0;
      wptr_q <= 1'b0;
      count_q <= '0;
      pending_q <= 1'b0;
    end else begin
      pending_q <= issue;
      if (pending_q) wptr_q <= ~wptr_q;
      if (pop) rptr_q <= ~rptr_q;
      case ({pending_q,pop})
        2'b10: count_q <= count_q + 2'd1;
        2'b01: count_q <= count_q - 2'd1;
        default: ;
      endcase
    end
  end
  always_ff @(posedge clk)
    if (rst_n && pending_q) data_q[wptr_q] <= mem_dout;
endmodule

With an always-ready sink, after fill one old response can pop while the next returns and another read is issued. With a stalled sink, reserved capacity stops launches before overflow. The response is captured once, never reconstructed by reading an unheld SRAM output later. Assert count_q+pending_q<=2, output stability while stalled, and accepted-read/response order and conservation. For four banks, register the accepted bank ID through the same latency, or capture per-bank outputs first and merge ordered tagged responses. This core's combinational ready path is allowed by the question; cutting it requires additional reservation capacity. HDL compilation is unverified here.

Claude Answer

2. Code: read skid wrapper (registered rd_ready, no downstream ready in the CEN cone)
// 1-cycle-latency SRAM read -> valid/ready. Three slots: one head + two skid,
// so rd_ready depends only on flops and full throughput holds with a registered credit.
module sram_rd_skid #(parameter int AW = 10, parameter int DW = 64) (
  input  logic          clk, rst_n,
  input  logic          rd_valid,       // from a flop upstream
  output logic          rd_ready,
  input  logic [AW-1:0] rd_addr,
  output logic          mem_cen_n,      // read enable, active low
  output logic [AW-1:0] mem_addr,
  input  logic [DW-1:0] mem_dout,       // valid the cycle after mem_cen_n == 0
  output logic          rresp_valid,
  input  logic          rresp_ready,
  output logic [DW-1:0] rresp_data
);
  localparam int DEPTH = 3;

  logic          launch, launch_q, pop;
  logic [1:0]    occ_q, wp_q, rp_q;     // occupancy 0..3, mod-3 pointers
  logic [DW-1:0] buf_q [DEPTH];

  // credit: held + in-flight must leave one slot for the read we launch now
  assign rd_ready  = ({1'b0, occ_q} + {2'b0, launch_q}) < 3'd3;
  assign launch    = rd_valid & rd_ready;
  assign mem_cen_n = ~launch;
  assign mem_addr  = rd_addr;

  assign rresp_valid = (occ_q != 2'd0);
  assign rresp_data  = buf_q[rp_q];
  assign pop         = rresp_valid & rresp_ready;

  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      launch_q <= 1'b0; occ_q <= '0; wp_q <= '0; rp_q <= '0;
    end else begin
      launch_q <= launch;
      if (launch_q) wp_q <= (wp_q == 2'd2) ? 2'd0 : wp_q + 2'd1;
      if (pop)      rp_q <= (rp_q == 2'd2) ? 2'd0 : rp_q + 2'd1;
      occ_q <= occ_q + {1'b0, launch_q} - {1'b0, pop};
    end
  end

  // the only load on mem_dout: a flop D pin through its enable
  always_ff @(posedge clk)
    if (launch_q) buf_q[wp_q] <= mem_dout;
endmodule

Invariant: occ + launch_q ≤ 3 after every cycle, so the in-flight word always has a slot
(zero loss). Steady state with rresp_ready = 1: occ = 1, launch_q = 1, sum 2 < 3, so
one launch per cycle. The same-address bypass reuses the push: buf_q[wp_q] <= bypass_q ? wdata_q : mem_dout.

M12Q18 · B3. (5 min) Timing Closure on mem_dout

  1. (5 min) Timing Closure on mem_dout.
    The foundry datasheet says T_ck_q of the 1024×64 macro is 520 ps at the slow corner
    (out of a 1562 ps clock period at 640 MHz). Look at the 4-to-1 bank read-data mux and your
    skid buffer: what is on the mem_dout path, and how do you structure the RTL so physical
    design can place a flop right next to each SRAM macro's output pins?

Gemini Answer

GPT Answer

At 640 MHz the period is 1562.5 ps. A 520 ps macro clock-to-output leaves about 1042.5 ps before destination setup, skew/uncertainty, wiring and mux delay. Prefer one local capture flop bank beside each macro and move the 4:1 selection after those registers, with aligned bank-ID/valid. Add a pipeline stage if required and extend the reservation accounting; do not keep assuming one-cycle response latency after adding registers.

Claude Answer

520 ps T_ck_q plus wire leaves ~1 ns. Nothing but a flop D pin may sit on mem_dout: no
4:1 bank mux, no ECC, no compare. Structure: instantiate this wrapper per bank, physically
next to its macro, so each buf_q is the capture flop for that macro; keep a 2-bit
bank-order FIFO (depth 3) on the issue side and mux the four wrappers' rresp_data
(registers) by the head of that FIFO. The 4:1 mux, ECC and anything else then run flop to
flop. If the mux must live far away, add one more plain capture stage per macro and make
the wrapper 2-cycle (launch_q, launch_qq, four slots).

M12Q19 · B4. (5 min) Sleep and Margin Wrapper

  1. (5 min) Sleep & Margin Wrapper.
    Add the logic that puts idle banks into Light Sleep (LS) after N idle cycles and wakes
    them up cleanly (requiring 1 cycle of LS=0 before CEN_N=0).

Gemini Answer

GPT Answer

Per bank: ACTIVE -> idle counter -> SLEEP -> WAKE -> ACTIVE. Enter sleep only after all accepted operations are captured, the output-valid contract is protected, and no unavoidable write is imminent. While sleeping/waking, CEN remains inactive. Deassert LS, wait a full specified wake cycle, then permit access. Keep RM/EMA at qualified settings.

Unstallable-write constraint: an arbitrary write arriving at a sleeping bank cannot be accepted with zero notice and a one-cycle wake requirement. Sequential addresses provide lookahead: keep the next-write bank awake and prewake the following bank early enough after each accepted write; initialize all banks awake until this invariant is established. If the next address cannot be predicted or software may replace it without notice, do not sleep write-targetable banks without an external wake/idle contract or sufficient write buffering. Reads may stall during wake. A generic idle counter alone is incorrect.

Claude Answer

Per bank: idle counter idle_q resets on any CEN=0 or pending access and counts up
otherwise; when idle_q == N set ls_q. Wake: a request to a bank with ls_q set clears
ls_q at the edge and sets woke_q for one cycle; bank_ok = !ls_q && !woke_q, so the
first CEN=0 comes one full cycle after LS fell. Reads see bank_ok in rd_ready; writes
can't stall, so they enter the write buffer while the bank wakes and commit next cycle. Never
sleep a bank with a read in flight (DOUT not yet captured) or a buffered write pending.
CEN is qualified with bank_ok inside the wrapper so no glitch can reach a sleeping
macro, and an SVA checks !(cen_n == 0 && ls == 1) and the one-cycle wake gap.

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

M12Q20 · C1. Questions for the interviewer

Gemini Answer

  1. "What is the standard memory wrapper architecture here—do RTL designers instantiate logical memory arrays that get mapped by a script, or explicit bank wrappers?"
  2. "Which SRAM tables in your MAC require SECDED ECC versus simple parity or no protection?"
  3. "How do you coordinate SRAM macro placement and pipeline flop budgeting with the Physical Design team during floorplanning?"

GPT Answer

What are the exact collision/wake timing tables? Are macro wrappers generated? What bandwidth is guaranteed under bank conflict, rather than only at peak nonconflicting traffic?

Claude Answer

  1. What is the rule here for flopping SRAM inputs and outputs, and is it enforced by lint?
  2. Are wrappers generated from a script (MBIST, repair, margin pins) or hand-maintained?
  3. How early do RTL designers get the compiler datasheets and T_ck_q numbers?