Ready-Valid Handshake Protocol Explained for RTL Engineers

When two RTL modules need to exchange data, simply connecting a data bus between them is not enough. The receiving module may not always be ready to accept data, while the transmitting module may have new data available at a different time.

The ready-valid handshake protocol solves this problem with two control signals: valid and ready.

The source uses valid to indicate that it has valid data available, while the destination uses ready to indicate that it can accept the data. A data transfer takes place on a clock edge when both signals are high. This simple mechanism is widely used in RTL pipelines, streaming interfaces, and protocols such as AXI4-Stream.

For RTL engineers, understanding the ready-valid handshake is important because incorrect handling of these signals can result in dropped data, duplicated transactions, pipeline stalls, or even deadlock.

What Is a Ready-Valid Handshake?

A ready-valid interface normally consists of:

  • valid – asserted by the source when valid data is available
  • ready – asserted by the destination when it can accept data
  • data – the information being transferred
  • clk – the common clock used by the interface

A transfer occurs when:

valid = 1

ready = 1

 

at the active clock edge.

Conceptually:

             Ready-Valid Interface

 

       Source                         Destination

          |                               |

          |—— data ——————>|

          |—— valid —————–>|

          |<—– ready ——————|

          |                               |

          +—- Transfer when both = 1 —+

 

The important point is that neither valid nor ready alone means that a transfer has occurred.

For example:

VALID

READY

Transfer

0

0

No

0

1

No

1

0

No

1

1

Yes

This behavior is also reflected in current AMD documentation for ready/valid interfaces, where a valid transfer occurs when both READY and VALID are high at the relevant rising clock edge.

 

How the Ready-Valid Handshake Works

Consider a producer that has a 32-bit data word to send.

The producer asserts:

valid = 1

data  = 32’h12345678

 

The consumer is currently busy, so it keeps:

ready = 0

 

No transfer occurs.

The producer must keep valid asserted and maintain the corresponding data until the destination becomes ready.

When the consumer eventually asserts:

ready = 1

 

the next active clock edge completes the transfer.

Cycle       VALID       READY       Transfer

————————————————

1             1           0          No

2             1           0          No

3             1           1          Yes

4             0           1          No

 

This is the basic mechanism behind ready-valid flow control.

 

What Does VALID Mean?

The valid signal is controlled by the source.

When valid is high, the source is saying:

“I have a valid transaction available on the data bus.”

The source should not assert valid merely because it expects the destination to be ready.

Instead, valid should indicate that the source actually has a transaction to send.

One of the most important rules is:

The source must not wait for ready before asserting valid.

If both sides wait for the other to act first, the interface can deadlock. SystemVerilog.dev specifically identifies this as a common ready-valid design pitfall.

 

What Does READY Mean?

The ready signal is controlled by the destination.

When ready is high, the destination is indicating:

“I can accept a transaction.”

The destination may assert ready before valid arrives.

For example:

READY = 1

VALID = 0

 

does not transfer anything.

But if the source subsequently asserts valid:

READY = 1

VALID = 1

 

the transfer can occur on the next active clock edge.

This ability for either side to independently indicate its state makes the ready-valid protocol useful for modular RTL design.

 

The Most Important Ready-Valid Rule

Suppose the source asserts:

valid = 1

data  = A

 

but the destination has:

ready = 0

 

The source must hold the transaction.

It should not change the data to B simply because the destination has not accepted A.

Conceptually:

Cycle       VALID       READY       DATA

——————————————

1             1           0          A

2             1           0          A

3             1           0          A

4             1           1          A

 

The transfer occurs in Cycle 4.

After that transfer, the source can present the next transaction.

This rule prevents the receiver from sampling inconsistent or changing data.

For AXI-style interfaces, the same principle applies: once VALID is asserted, the associated transfer information must remain stable until the handshake completes.

 

Ready-Valid Handshake Timing

A simple timing sequence can be represented as:

       | 1 | 2 | 3 | 4 | 5 |

CLK     |↑  |↑  |↑  |↑  |↑  |

 

VALID   | 0 | 1 | 1 | 1 | 0 |

READY   | 0 | 0 | 1 | 1 | 1 |

DATA    | – | A | A | B | – |

 

                 ^

             Transfer A

 

At Cycle 3:

VALID = 1

READY = 1

 

Therefore, data A is transferred.

If the source has another transaction immediately available, it can keep VALID high and place the next data item on the bus.

This allows one transfer per clock cycle when both sides remain ready.

 

Ready-Valid Handshake and Backpressure

One of the biggest advantages of the ready-valid protocol is backpressure.

Backpressure occurs when a downstream module temporarily cannot accept more data.

For example:

Module A → Module B → Module C

 

If Module C becomes busy, Module B may eventually stop accepting data from Module A.

The ready signal propagates this condition backward.

Module A

   |

   v

Module B

   |

   v

Module C

   |

   X Busy

 

Module C can deassert ready.

Module B then stops accepting additional data when its available buffering is exhausted.

This prevents uncontrolled data flow and helps connect pipelines with different processing rates.

Ready-valid interfaces are therefore particularly useful in streaming and pipelined RTL architectures.

 

Ready-Valid Handshake in RTL

A simple SystemVerilog interface might look like this:

module data_source #(

    parameter int WIDTH = 32

)(

    input  logic             clk,

    input  logic             rst_n,

 

    output logic             valid,

    output logic [WIDTH-1:0] data,

    input  logic             ready

);

 

    always_ff @(posedge clk or negedge rst_n) begin

        if (!rst_n) begin

            valid <= 1’b0;

            data  <= ‘0;

        end

        else begin

            if (!valid || ready) begin

                valid <= 1’b1;

                data  <= next_data;

            end

        end

    end

 

endmodule

 

The exact implementation depends on the behavior of the source, but the important principle is that the source retains the transaction while valid is high and ready is low.

The transfer condition can be expressed as:

assign transfer = valid && ready;

 

At every active clock edge where this condition is true, one transaction is accepted.

 

Why VALID Must Not Wait for READY

Consider this incorrect behavior:

Source:

if (ready)

    valid = 1;

 

and:

Destination:

if (valid)

    ready = 1;

 

Now both modules can wait indefinitely.

The source waits for ready.

The destination waits for valid.

Neither signal becomes active.

This is a classic deadlock scenario.

A safer design is:

Source:

valid depends on whether data is available

 

Destination:

ready depends on whether it can accept data

 

The two signals should be generated independently enough that the interface can make progress.

 

Avoid Combinational Loops

Another important RTL design issue occurs when valid and ready are connected through combinational dependencies.

For example:

Source VALID  —> Destination READY

       ^                    |

       |____________________|

 

If the source calculates valid directly from ready, while the destination calculates ready directly from valid, the design can create a combinational loop.

This can lead to:

  • Timing problems
  • Unpredictable simulation behavior
  • Difficult synthesis
  • Poor scalability
  • Potential deadlock

SystemVerilog.dev recommends avoiding such combinational loops in ready-valid interfaces and using registered signals or state-based logic where appropriate.

 

Ready-Valid Handshake vs Request-Acknowledge

Ready-valid and request-acknowledge handshakes are related but should not be treated as identical protocols.

Feature

Ready-Valid

Request-Acknowledge

Main signals

valid, ready

req, ack

Typical use

Streaming data

Control/event transfer

Data transfer

valid && ready

Depends on protocol

Backpressure

Naturally supported

Can be implemented

Common application

RTL pipelines, AXI streams

Control interfaces

Ready-valid is especially effective when a design needs continuous data movement and flow control.

 

Ready-Valid Handshake and AXI

The ready-valid mechanism is strongly associated with AMBA AXI, particularly AXI4-Stream.

However, ready-valid is not limited to AXI.

It is a general RTL interface pattern that can be used whenever one synchronous module needs to transfer transactions to another while allowing the destination to control the flow rate.

AXI4-Stream uses the same fundamental idea: a transfer occurs when VALID and READY are asserted at the appropriate clock edge.

This is why understanding ready-valid signaling is useful before learning more complex AXI interfaces.

 

Common Ready-Valid Handshake Mistakes

1. Deasserting VALID before the transfer

If:

VALID = 1

READY = 0

 

the source should not withdraw the transaction.

It should keep the transaction available until the destination accepts it.

2. Changing DATA while VALID is waiting

Changing data while valid remains asserted and ready is low can cause the receiver to observe the wrong transaction.

3. Making VALID depend directly on READY

This can introduce deadlock.

4. Creating a combinational READY-VALID loop

This can create problematic timing paths between connected modules.

5. Assuming VALID alone means transfer

It does not.

The transfer condition is:

valid && ready

 

6. Ignoring backpressure

A downstream module may temporarily stop accepting data. The upstream logic must handle this condition correctly rather than continuously overwriting or discarding transactions.

 

How to Verify a Ready-Valid Interface

Ready-valid interfaces should be verified for both normal transfers and stalled conditions.

Important scenarios include:

  • VALID=0, READY=0
  • VALID=0, READY=1
  • VALID=1, READY=0
  • VALID=1, READY=1
  • Multiple consecutive transfers
  • Destination stalls for several cycles
  • Source stalls before producing data
  • Reset during idle operation
  • Reset followed by immediate traffic
  • Back-to-back transactions

A useful SystemVerilog assertion is to check that data remains stable when a transaction is waiting:

property valid_data_stable;

    @(posedge clk)

    disable iff (!rst_n)

    valid && !ready |=> valid && $stable(data);

endproperty

 

assert property (valid_data_stable);

 

Inskill’s existing material on assertion-based verification also demonstrates checking valid-ready behavior using SystemVerilog Assertions, so this topic naturally connects to verification-oriented RTL learning.

 

Ready-Valid Handshake: Key Takeaways

The ready-valid handshake protocol is one of the most useful interface patterns for RTL engineers.

The concept is simple:

VALID = Source has a transaction

READY = Destination can accept it

 

Transfer = VALID && READY

 

But the implementation details matter.

When valid is high and ready is low, the source must continue presenting the same transaction. The source should not wait for ready before making valid active, because doing so can create deadlock. Designers should also avoid inappropriate combinational dependencies between ready and valid.

Once these rules are understood, ready-valid interfaces become much easier to apply to RTL pipelines, streaming data paths, AXI interfaces, DMA engines, FIFOs, and other SoC communication structures.

For an RTL engineer, mastering this protocol is less about memorizing two signals and more about understanding data stability, flow control, backpressure, throughput, and safe module-to-module communication.

Leave a Reply

Your email address will not be published. Required fields are marked *