The Skid Buffer
High-performance SoCs use valid and ready handshaking protocols to transfer data between pipeline stages. Chaining multiple pipeline stages links the ready signals combinationally, creating a critical timing path that severely limits clock frequency. A skid buffer solves this by fully registering the upstream ready signal, breaking the combinational path while maintaining maximum throughput.
The module acts as a two-entry FIFO. Data from the source is accepted when both s_valid and s_ready are high. Data is presented to the destination along with m_valid. Because s_ready is a registered output, it cannot combinationally react to m_ready dropping. If the destination pauses by dropping m_ready, the source sees s_ready high for one additional cycle and may send one extra data word. The skid buffer absorbs this extra word into a secondary skid register. When the destination becomes ready again, the skid data is forwarded to the main register.
- Clock edge:
posedge clk - Reset type: Asynchronous, active-low (
rst_n) - Reset state:
s_readyis 1,m_validis 0,m_datais 0 - Priority: Reset has highest priority.
Cycle 1: rst_n=0 → s_ready=1, m_valid=0, m_data=0 Cycle 2: rst_n=1, s_valid=1, s_data=A, m_ready=1 → s_ready=1, m_valid=1, m_data=A (Data flows to main register) Cycle 3: s_valid=1, s_data=B, m_ready=0 → s_ready=0, m_valid=1, m_data=A (Destination stalls; Buffer absorbs B into skid register. Buffer is now full, so s_ready drops) Cycle 4: s_valid=1, s_data=C, m_ready=0 → s_ready=0, m_valid=1, m_data=A (Source tries to send C, but s_ready is 0. C is ignored) Cycle 5: s_valid=0, s_data=0, m_ready=1 → s_ready=1, m_valid=1, m_data=B (Destination accepts A. B moves from skid to main register. Buffer has space, s_ready goes high) Cycle 6: s_valid=0, s_data=0, m_ready=1 → s_ready=1, m_valid=0, m_data=B (Destination accepts B. Buffer is empty)
{ "signal": [
{ "name": "clk", "wave": "p......" },
{ "name": "rst_n", "wave": "01....." },
{ "name": "s_valid", "wave": "011100." },
{ "name": "s_data", "wave": "=.====.", "data": ["0", "A", "B", "C", "0", "0"] },
{ "name": "m_ready", "wave": "010011." },
{},
{ "name": "s_ready", "wave": "1..0.1." },
{ "name": "m_valid", "wave": "0.1...0" },
{ "name": "m_data", "wave": "=.====.", "data": ["0", "A", "A", "B", "B"] }
], "head": { "text": "Skid buffer absorbing an extra transfer when m_ready drops." } }| Signal | Direction | Width | Description | |--------|-----------|-------|-------------| | clk | input | 1 | Positive-edge triggered clock | | rst_n | input | 1 | Asynchronous active-low reset; resets all state | | s_valid | input | 1 | Source data valid | | s_data | input | 8 | Source data payload | | s_ready | output | 1 | Source ready; fully registered, 1 on reset | | m_valid | output | 1 | Destination data valid; fully registered, 0 on reset | | m_data | output | 8 | Destination data payload; fully registered, 8'b0 on reset | | m_ready | input | 1 | Destination ready |
Constraints
- Clock edge is
posedge clk. - Reset is asynchronous, active-low
rst_n. - On reset,
s_readymust be 1,m_validmust be 0, andm_datamust be 0. - The module must provide full throughput: if both source and destination are ready, one data word transfers every clock cycle.
- All outputs (
s_ready,m_valid,m_data) must be driven directly by flip-flops. There must be no combinational paths from any input to any output. - If
s_readyis 0, incomings_validands_datamust be ignored. m_datamust hold its last valid value whenm_validtransitions to 0.
Topics
Solve this problem
Write the module in Verilog, SystemVerilog or VHDL. Your submission is compiled and simulated against a real testbench — you get the waveform back, not a stored answer.
This problem is part of Codiode Pro. The statement above is free to read.
The circuit builder and code editor need a desktop screen. On a phone, read the problem here and open it on a laptop to solve.