← 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
- Part A — Rapid-fire Q and A (0:05–0:20)
- M12Q2 · A1. Compare a flip-flop array, a compiled Register File (1R1W…
- M12Q3 · A2. Why is CLK → DOUT on a compiled SRAM so much slower than a…
- M12Q4 · A3. You put a compiled SRAM inside a valid/ready pipeline. On…
- M12Q5 · A4. What happens in a 1R1W (two-port) SRAM when the read port…
- M12Q6 · A5. Byte-write mask (BWEN / WMASK) vs. bit-write mask: if a…
- M12Q7 · A6. Why split one 4096 × 64 SRAM into four 1024 × 64 banks…
- M12Q8 · A7. What are the EMA / RM (Extra Margin Adjustment / Read…
- M12Q9 · A8. Describe the three low-power modes of a modern SRAM macro:…
- M12Q10 · A9. Why does an SRAM wrapper include an isolation clamp or…
- M12Q11 · A10. ECC vs. parity on SRAMs: when do you use single-bit…
- M12Q12 · A11. If an SRAM with SECDED ECC detects a correctable 1-bit…
- M12Q13 · A12. In your UCLA Hardware Neural Network Accelerator (ternary…
- M12Q14 · A13. Why do synthesis and STA engineers hate it when you drive…
- M12Q15 · A14. What ports does an SRAM wrapper expose to the DFT / MBIST…
- Part B — Deep dive: 1R1W Emulation using Single-Port (1RW) SRAM Banks +…
- Part C — Your questions (0:55–1:00)
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
- Answer:
- Wi-Fi MAC:
- TX/RX Elastic Packet Buffers: Banked Single-Port (1RW) or Pseudo-Dual-Port (1R1W) SRAM macros (where DMA writes into one side while the PHY stream reads out the other).
- Beacon Template & Key Table RAMs: Single-Port (1RW) SRAMs (arbitrated between rare firmware APB updates and hardware TBTT/crypto reads, with Light Sleep enabled between beacons).
- BlockAck (BA) Scoreboard & Sequence Number Tables: Latency-critical 1R1W Compiled Register Files (RFs) so SIFS response generation can read and update a peer's 256/1024-bit bitmap in 1–2 cycles.
- UCLA Hardware Neural Network Accelerator:
- Weight & Activation Scratchpads: Banked 1RW SRAMs packing multiple 2-bit ternary weights per word so one single-port read per cycle fed 16–32 parallel ternary MAC units simultaneously, cutting SRAM dynamic read power by an order of magnitude.
- Wi-Fi MAC:
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
- Area per bit (smallest / densest to largest):
- Single-Port (1RW) 6T High-Density SRAM (
baseline) - Pseudo-Dual-Port (1R1W) 8T Two-Port SRAM (
) - Compiled 1R1W Register File (RF) (
, faster T_ck_q, shallower max depth) - True Dual-Port (2RW) 8T/10T SRAM (
) - Standard-Cell Flip-Flop Array + Muxes (
)
- Single-Port (1RW) 6T High-Density SRAM (
- Crossover point between Flops and Compiled Macro: Typically around 1 Kbit to 2 Kbits (e.g.,
or ). Below ~1 Kbit, the fixed periphery overhead of an SRAM macro (sense amplifiers, row/column decoders, self-timed clock generator, MBIST collar, and physical placement halo) outweighs the bitcell savings.
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
- Why slow: Unlike a flip-flop driven by a strong CMOS inverter, an SRAM bitcell pulls down a long, high-capacitance metal bitline with a minimum-sized pass-gate transistor until a differential sense amplifier fires—taking 400–600 ps in a 640 MHz (1562 ps) cycle.
- Golden RTL rule:
- Inputs (
CEN,WEN,BWEN,ADDR,DIN): Must come directly from flip-flopQoutputs (at most 1–2 levels of 2:1 MBIST/arbitration muxing). - Outputs (
DOUT): Must go directly into a capture/pipeline flip-flop placed physically adjacent to the macro pins before any wide arithmetic or deep muxing.
- Inputs (
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 , CEN=0 (read issued). On cycle , 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
- When you assert
CEN = 0on cycle, the SRAM outputs DOUTon cycle. - If downstream
out_readydrops to0on cycle, you cannot hold DOUTon the SRAM pins across cycleif another read was already pipelined behind it, or if the SRAM enters precharge/sleep, or if the macro doesn't guarantee output hold when CEN = 1. - Therefore, you must place a skid/holding register stage on
DOUT(or track in-flight read credits so a read is only launched at cyclewhen a downstream holding slot is guaranteed free at cycle ).
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
- What happens in the macro: Firing the Read Wordline (
RWL) and Write Wordline (WWL) on the same row in the same cycle causes bitline contention: the simulation model outputs64'hXXXX_XXXX_XXXX_XXXXonDOUT(and in silicon can return half-written garbage or disturb the write). - How RTL prevents it: Add collision detection logic
wire addr_clash = rd_en && wr_en && (raddr == waddr);:- Gate off the physical SRAM read enable:
sram_rcen_n = ~(rd_en && !addr_clash); - Register
addr_clash_qandwdata_q, and muxwdata_qonto the read output on cycle(Write-Through / Bypass Forwarding), giving clean, deterministic new-data semantics with zero X-propagation!
- Gate off the physical SRAM read enable:
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
- Pipeline: Updating a 4-bit field inside a 64-bit word without bit-write masks requires Stage 0 (Read 64b word at
addr)Stage 1 (Modify 4 bits & Write 64b word back to addr). - Back-to-back RAW hazard: If cycle
updates addr = Aand cyclealso updates addr = A, Stage 0 at cyclereads the SRAM before Stage 1 from cycle has written its modified word back—overwriting cycle 's update! - Fix: Detect
rmw_s0_valid && rmw_s1_valid && (addr_s0 == addr_s1)and bypass Stage 1's modified 64-bit write data directly into Stage 1 on the next cycle (and suppress the redundant SRAM read atto save power).
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 SRAM into four banks instead of using a single macro? Give one dynamic power reason, one floorplan/timing reason, and one bandwidth reason.
Gemini Answer
- Dynamic Power (~60% lower): Each read/write only precharges and discharges bitlines that are
as tall ( cells per bitline instead of ), and the other 3 idle banks stay unselected ( CEN_N = 1). - Timing & Floorplan: Shorter bitlines reduce
T_ck_qby ~100–150 ps, and four smaller macros can be placed along the perimeter of the floorplan without blocking global routing channels. - Bandwidth (up to
): 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
- What they are: 3-to-4-bit static configuration pins on compiled SRAM macros that adjust the internal self-timed sense-amplifier firing delay and wordline pulse width.
- Who sets them & why post-silicon: Foundry characterization specifies default values per speed/voltage corner, but if post-silicon characterization finds a slow-sense-amp silicon lot (or wants to run at a lower
), firmware/eFuse can bump EMAbyto trade ~40 ps of T_ck_qfor higher bitcell read stability. - How wired in RTL: Driven from a top-level quasi-static CSR / eFuse bus (with
set_false_pathin SDC).
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
- Light Sleep (
LS): Gates internal periphery clocks and biases off sense-amp/decoder precharge; retains array data; fast 1-cycle wakeup beforeCEN_N = 0. - Deep Sleep (
DS): Lowers array periphery rail / raises source virtual ground (VSSM) to cut bitcell leakage by ~50–70%; retains array data; requires 2 to 4 cycles wakeup beforeCEN_N = 0. - Shut Down (
SD): Opens the internal header/footer power switch completely; destroys all array data (near-zero leakage); requires a multi-cycle sequenced wakeup + array re-initialization before use.
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
- Foundry SRAM Verilog simulation models (and silicon bitcells) have a strict timing check: if
CEN_N == 0whileLS/DS/SDasserts, deasserts, or is within the-cycle wakeup window, the wordline can glitch while the bitcell rail is drooping, corrupting the entire row (the Verilog model immediately wipes the entire mem[]array to64'hX!).
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
- Parity (1 bit per byte/word): Detects 1-bit soft errors (SER); used on read-only/clean buffers (like instruction caches or beacon templates) where firmware can simply drop the packet or reload from DRAM.
- SECDED ECC (e.g., 8 Hamming/Hsiao parity bits over 64 data bits = 72-bit SRAM): Corrects any 1-bit flip on the fly and detects any 2-bit flip; mandatory for state tables, descriptors, or packet buffers with no backup copy.
- Why SECDED clashes with sub-word byte writes: The 8 ECC bits are a function of all 64 data bits. You cannot write 1 byte into a 72-bit SECDED SRAM without either (a) doing a Read-Modify-Write of all 64 bits to recompute the 8 ECC bits, or (b) storing separate ECC/parity per byte lane (huge bit overhead).
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
- Ternary weights: Encode each weight in 2 bits (32 weights per 64-bit SRAM word) or pack 5 ternary trits (
) into every 8-bit byte (40 weights per 64-bit word = , achieving 99% of the theoretical entropy limit with a tiny 243-entry 8-bit LUT unpacker!). - 48-bit MAC entries: Either use a native 48-bit (or 56-bit with ECC) compiled macro width, or pack four 48-bit entries across three 64-bit words (
bits).
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
- Inside the SRAM macro,
CEN_Nfeeds the internal self-timed clock-pulse generator and has the largest setup time () of any pin on the macro (often 200–300 ps). Putting 10 levels of address decode or arbitration logic in front of CEN_Nleaves almost no time for wire routing to the macro's physical corner.
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
- Wrapper ports:
bist_mode(tm),bist_cen_n,bist_wen_n,bist_bwen_n,bist_addr,bist_din,bist_dout(or internal comparatorbist_fail), plus fuse repair shift pins (bisr_si,bisr_so,bisr_clk,bisr_en). - Why functional RTL stays outside: Keeps the MBIST collar 100% uniform and auto-generated by Tessent/SMS across 200 SRAM instances, and ensures only the single 2:1
bist_modemux sits on the criticalCEN_N/ADDRsetup path.
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).
- A single 4096×64 2-Port (1R1W) macro is too large and fails 640 MHz timing.
- Instead, you have four 1024×64 Single-Port (1RW) SRAM macros (
bank[3:0]), each taking
either one read or one write per cycle, with a 1-cycle read latency (CEN=0at cycle
→DOUTvalid at cycle, no output hold guarantee if CENchanges or Light Sleep
asserts).Traffic constraint from the MAC architecture:
- Writes arrive sequentially by address (
waddrincrements by 1 on every write), at most 1
write per cycle (wr_validhas nowr_ready— writes cannot be stalled).- Reads (
rd_valid/rd_ready/rd_addr[11:0]) may be random-access, up to 1 per cycle, and
drive a downstreamrresp_valid/rresp_ready/rresp_data[63:0]pipeline that can exert
backpressure (rresp_ready = 0).
M12Q16 · B1. (10 min) Bank Mapping and Conflict Arbitration
- (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 whenrd_addr == wr_addrin the same cycle?- Adding a tiny 4-entry flop cache / write-buffer completely eliminates read stalls under
sequential writes — explain how, or explain the simplerrd_readystall scheme and its
throughput bound.
Gemini Answer
- Low-Order Interleaving (
bank_sel = addr[1:0],row_addr = addr[11:2]):- Why: Since writes increment
waddrsequentially byon every write ( 0, 1, 2, 3, 4...), low-order interleaving cycles writes evenly acrossBank 0 -> Bank 1 -> Bank 2 -> Bank 3, and sequential packet reads also step across banks in lockstep!
- Why: Since writes increment
- Bank Conflict Handling:
- Case A (
rd_valid && wr_valid && rd_addr[1:0] == wr_addr[1:0]withrd_addr != wr_addr): Both want different rows of the same 1RW bank. Since writes cannot stall (wr_validalways wins its bank), deassertrd_ready = 0for 1 cycle. Because the next write incrementswr_addr + 1to(bank + 1) mod 4, the read tord_addr[1:0]is guaranteed 100% conflict-free on the very next cycle (bounded 1-cycle max stall)! - Case B (Same exact address
rd_addr == wr_addrwhenwr_valid == 1): Don't even stall! Let the write go into the SRAM bank, accept the read (rd_ready = 1), and bypasswr_datainto a 1-cycle forwarding flop sorresp_datareturns the newly written word on cycle! - Zero-Stall 4-Entry Write Cache Enhancement (Optional Staff bonus): If you hold each incoming sequential write in a tiny 4-entry flip-flop staging ring (
wbuf[bank]) and drain a bank'swbuf[b]to the 1RW SRAM on any cycle whererd_bank != b, reads never stall even once because with 1 read/cycle at least 3 of the 4 banks are always free for draining writes!
- Case A (
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
- Low-order interleave:
bank_sel = addr[1:0],row = addr[11:2]. Sequential writes rotate
through all four banks, so a random read collides with the write bank one cycle in four;
high-order banking would pin a whole write burst to one bank and starve reads of it. - Same bank, same cycle: the write wins (it can't stall),
rd_readydrops for one cycle.
Because the write bank rotates, a retried read never collides twice in a row: worst case
50% read throughput, 75% expected. Same address, same cycle: skip the SRAM and bypass
wdatainto the response pipeline as if it had been read. - Write buffer: a 4-entry flop queue takes every write; it commits to a bank only in cycles
when the read doesn't want that bank. Reads check the queue (4-entry CAM) and bypass on a
hit, so ordering holds. With random reads the queue never fills; with an adversarial read
stream to one bank, the write for that bank waits, so the rule is "write wins when the
queue has 3 entries", which bounds the queue and keeps reads at ≥ 75%.
M12Q17 · B2. (15 min) Live Coding — SRAM Read-to-Valid/Ready Skid Wrapper
- (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_datainterface with zero read loss under arbitrary
downstream backpressure and full 1-read-per-cycle throughput.
(Hint: whenmem_cen_n == 0on cycle, the data arriving on mem_doutin cycle
is already in flight — where must it go ifrresp_readyis 0 on cycle?)
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
- (5 min) Timing Closure on
mem_dout.
The foundry datasheet saysT_ck_qof 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 themem_doutpath, 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
- Problem: If
bank[0..3].doutroutes acrossof floorplan into a central 64-bit 4:1 mux and then through the skid mux before hitting out_data_q,520 ps (SRAM) + 350 ps (wire) + 250 ps (muxes) = 1120 ps, which leaves zero margin after clock skew/uncertainty. - Physical-Aware RTL Solution: Instantiate a local 64-bit capture flip-flop
bank_dout_q[b]directly inside each bank's collar wrapper (enabled bybank_rd_inflight_q[b]).- Then
bank[b].douttravelsinto bank_dout_q[b].Dwith zero combinational logic in between (closing withslack!). - The 4:1 bank mux and skid logic sit on the next cycle (
bank_dout_q[0..3] -> mux4 -> skid).
- Then
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
- (5 min) Sleep & Margin Wrapper.
Add the logic that puts idle banks into Light Sleep (LS) afteridle cycles and wakes
them up cleanly (requiring 1 cycle ofLS=0beforeCEN_N=0).
Gemini Answer
- Maintain a per-bank idle counter
idle_cnt_q[b]:- Whenever bank
bhasrd_req[b] || wr_req[b], resetidle_cnt_q[b] <= '0. - When
idle_cnt_q[b] == SLEEP_THRESH(e.g., 16 idle cycles) andmem_cen_n[b] == 1, assertmem_ls[b] <= 1'b1. - Wakeup rule (1 cycle
LS=0beforeCEN_N=0): Since writes are sequential (wr_addrincrements by 1), when a write hits bank(b - 1) mod 4, pre-wake bankb(mem_ls[b] <= 1'b0) 1 cycle early so bankbis already awake with 0 stall! If a random read targets a sleeping bankb, deassertmem_ls[b] <= 1'b0, forcemem_cen_n[b] = 1'b1andrd_ready = 1'b0for that 1 wakeup cycle, and execute the read on the next cycle.
- Whenever bank
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
- "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?"
- "Which SRAM tables in your MAC require SECDED ECC versus simple parity or no protection?"
- "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
- What is the rule here for flopping SRAM inputs and outputs, and is it enforced by lint?
- Are wrappers generated from a script (MBIST, repair, margin pins) or hand-maintained?
- How early do RTL designers get the compiler datasheets and
T_ck_qnumbers?