{"id":10126,"date":"2026-09-02T06:03:28","date_gmt":"2026-09-02T06:03:28","guid":{"rendered":"https:\/\/inskill.in\/training\/?p=10126"},"modified":"2026-09-15T06:06:22","modified_gmt":"2026-09-15T06:06:22","slug":"how-to-design-safe-handshake-logic-between-rtl-modules","status":"publish","type":"post","link":"https:\/\/inskill.in\/training\/vlsi\/how-to-design-safe-handshake-logic-between-rtl-modules\/","title":{"rendered":"How to Design Safe Handshake Logic Between RTL Modules"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"10126\" class=\"elementor elementor-10126\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-af99288 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"af99288\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-4a23e6b\" data-id=\"4a23e6b\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-9bd6dc1 elementor-widget elementor-widget-text-editor\" data-id=\"9bd6dc1\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><span style=\"font-weight: 400;\">Modern RTL designs rarely consist of one block doing everything. A typical SoC or digital system is divided into multiple modules, with each block responsible for a specific operation. One module may generate data, another may process it, and a third may store or forward the result.<\/span><\/p><p><span style=\"font-weight: 400;\">The difficult part is not simply connecting these modules with wires. The receiving module may be busy when data arrives, while the transmitting module may not have data available on every clock cycle. Without proper control logic, this can lead to lost data, duplicated transactions, overwritten values, or modules waiting indefinitely for each other.<\/span><\/p><p><span style=\"font-weight: 400;\">This is where handshake logic becomes important.<\/span><\/p><p><span style=\"font-weight: 400;\">A handshake provides an agreed mechanism for two RTL modules to communicate. The most common approach for synchronous data transfer is the ready-valid handshake, where the source indicates that data is available using <\/span><span style=\"font-weight: 400;\">valid<\/span><span style=\"font-weight: 400;\"> and the destination indicates that it can accept the data using <\/span><span style=\"font-weight: 400;\">ready<\/span><span style=\"font-weight: 400;\">. A transfer takes place when both signals are high at the active clock edge.<\/span><\/p><p><span style=\"font-weight: 400;\">For some control or clock-domain-crossing applications, a request-acknowledge handshake is more appropriate.<\/span><\/p><p><span style=\"font-weight: 400;\">The important point is that a handshake is not just two control signals. It is a protocol with rules that both sides must follow.<\/span><\/p><h3><span style=\"font-weight: 400;\">Why Is Handshake Logic Needed in RTL?<\/span><\/h3><p><span style=\"font-weight: 400;\">Consider two synchronous modules:<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Data<\/span><\/p><p><span style=\"font-weight: 400;\">Module A \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25ba Module B<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Control<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">Module A produces data, while Module B consumes it.<\/span><\/p><p><span style=\"font-weight: 400;\">Suppose Module A produces a new value every clock cycle, but Module B needs two cycles to process each value.<\/span><\/p><p><span style=\"font-weight: 400;\">If Module A continues sending data without knowing whether Module B can accept it, some values may be overwritten or lost.<\/span><\/p><p><span style=\"font-weight: 400;\">A handshake solves this problem by allowing the receiver to apply <\/span><b>backpressure<\/b><span style=\"font-weight: 400;\">.<\/span><\/p><p><span style=\"font-weight: 400;\">The source effectively says:<\/span><\/p><p><span style=\"font-weight: 400;\">&#8220;I have valid data available.&#8221;<\/span><\/p><p><span style=\"font-weight: 400;\">The destination responds:<\/span><\/p><p><span style=\"font-weight: 400;\">&#8220;I am ready to accept it.&#8221;<\/span><\/p><p><span style=\"font-weight: 400;\">Only when both conditions are true does the transfer occur.<\/span><\/p><p><span style=\"font-weight: 400;\">This approach allows independently designed RTL modules to communicate without assuming that both sides operate at exactly the same processing rate.<\/span><\/p><p>\u00a0<\/p><h3><span style=\"font-weight: 400;\">Ready-Valid Handshake: The Most Common RTL Approach<\/span><\/h3><p><span style=\"font-weight: 400;\">A basic ready-valid interface contains three signals:<\/span><\/p><p><span style=\"font-weight: 400;\">valid<\/span><\/p><p><span style=\"font-weight: 400;\">ready<\/span><\/p><p><span style=\"font-weight: 400;\">data<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">The source drives <\/span><span style=\"font-weight: 400;\">valid<\/span><span style=\"font-weight: 400;\"> and <\/span><span style=\"font-weight: 400;\">data<\/span><span style=\"font-weight: 400;\">.<\/span><\/p><p><span style=\"font-weight: 400;\">The destination drives <\/span><span style=\"font-weight: 400;\">ready<\/span><span style=\"font-weight: 400;\">.<\/span><\/p><p><span style=\"font-weight: 400;\">The fundamental transfer condition is:<\/span><\/p><p><span style=\"font-weight: 400;\">assign transfer = valid &amp;&amp; ready;<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">At a rising clock edge:<\/span><\/p><p><span style=\"font-weight: 400;\">valid = 0, ready = 0 \u2192 No transfer<\/span><\/p><p><span style=\"font-weight: 400;\">valid = 0, ready = 1 \u2192 No transfer<\/span><\/p><p><span style=\"font-weight: 400;\">valid = 1, ready = 0 \u2192 No transfer<\/span><\/p><p><span style=\"font-weight: 400;\">valid = 1, ready = 1 \u2192 Transfer<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">This behavior is also used extensively in industry-standard streaming interfaces. AMD documentation, for example, defines a valid transfer when <\/span><span style=\"font-weight: 400;\">READY<\/span><span style=\"font-weight: 400;\"> and <\/span><span style=\"font-weight: 400;\">VALID<\/span><span style=\"font-weight: 400;\"> are asserted at the rising clock edge.<\/span><\/p><p><span style=\"font-weight: 400;\">A useful way to remember the protocol is:<\/span><\/p><p><span style=\"font-weight: 400;\">VALID means &#8220;the source has something to transfer.&#8221;<\/span><\/p><p><span style=\"font-weight: 400;\">READY means &#8220;the destination can accept it.&#8221;<\/span><\/p><p><span style=\"font-weight: 400;\">VALID &amp;&amp; READY means &#8220;the transfer happens now.&#8221;<\/span><\/p><p>\u00a0<\/p><h3><span style=\"font-weight: 400;\">The Source Must Hold Data When the Receiver Is Not Ready<\/span><\/h3><p><span style=\"font-weight: 400;\">One of the most important rules is what happens when:<\/span><\/p><p><span style=\"font-weight: 400;\">valid = 1<\/span><\/p><p><span style=\"font-weight: 400;\">ready = 0<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">The source cannot assume that the transaction has completed.<\/span><\/p><p><span style=\"font-weight: 400;\">Instead, it must keep the transaction available until the destination accepts it.<\/span><\/p><p><span style=\"font-weight: 400;\">For example:<\/span><\/p><p><span style=\"font-weight: 400;\">always_ff @(posedge clk) begin<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0if (reset) begin<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0valid &lt;= 1&#8217;b0;<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0data\u00a0 &lt;= &#8216;0;<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0end<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0else if (valid &amp;&amp; ready) begin<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0valid &lt;= 1&#8217;b0;<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0end<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0else if (new_data) begin<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0data\u00a0 &lt;= input_data;<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0valid &lt;= 1&#8217;b1;<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0end<\/span><\/p><p><span style=\"font-weight: 400;\">end<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">The exact implementation will depend on the surrounding architecture, but the principle is critical:<\/span><\/p><p><span style=\"font-weight: 400;\">Once a source presents a valid transaction, it must not change the transaction simply because the destination is temporarily unable to accept it.<\/span><\/p><p><span style=\"font-weight: 400;\">Ready\/valid references similarly emphasize that data and <\/span><span style=\"font-weight: 400;\">valid<\/span><span style=\"font-weight: 400;\"> must remain stable while the source is waiting for <\/span><span style=\"font-weight: 400;\">ready<\/span><span style=\"font-weight: 400;\">.<\/span><\/p><p><span style=\"font-weight: 400;\">This prevents the receiver from sampling one value while the source has already moved to another.<\/span><\/p><p>\u00a0<\/p><h3><span style=\"font-weight: 400;\">A Simple RTL Handshake Example<\/span><\/h3><p><span style=\"font-weight: 400;\">Suppose one module sends an 8-bit value to another module.<\/span><\/p><p><span style=\"font-weight: 400;\">The interface could be:<\/span><\/p><p><span style=\"font-weight: 400;\">module producer (<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0input\u00a0 logic \u00a0 \u00a0 \u00a0 clk,<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0input\u00a0 logic \u00a0 \u00a0 \u00a0 rst_n,<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0input\u00a0 logic \u00a0 \u00a0 \u00a0 start,<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0input\u00a0 logic [7:0] input_data,<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0output logic \u00a0 \u00a0 \u00a0 valid,<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0output logic [7:0] data,<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0input\u00a0 logic \u00a0 \u00a0 \u00a0 ready<\/span><\/p><p><span style=\"font-weight: 400;\">);<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">The basic transfer event is:<\/span><\/p><p><span style=\"font-weight: 400;\">wire transfer;<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">assign transfer = valid &amp;&amp; ready;<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">The producer can capture the data and assert <\/span><span style=\"font-weight: 400;\">valid<\/span><span style=\"font-weight: 400;\">:<\/span><\/p><p><span style=\"font-weight: 400;\">always_ff @(posedge clk or negedge rst_n) begin<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0if (!rst_n) begin<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0valid &lt;= 1&#8217;b0;<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0data\u00a0 &lt;= 8&#8217;d0;<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0end<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0else begin<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if (start &amp;&amp; !valid) begin<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0data\u00a0 &lt;= input_data;<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0valid &lt;= 1&#8217;b1;<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0end<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0else if (transfer) begin<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0valid &lt;= 1&#8217;b0;<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0end<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0end<\/span><\/p><p><span style=\"font-weight: 400;\">end<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">The receiving module can indicate that it is able to accept data:<\/span><\/p><p><span style=\"font-weight: 400;\">assign ready = !busy;<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">The actual implementation may be more complex, but the fundamental relationship remains the same.<\/span><\/p><p>\u00a0<\/p><h3><span style=\"font-weight: 400;\">Never Make VALID Wait for READY<\/span><\/h3><p><span style=\"font-weight: 400;\">One of the most common handshake mistakes is creating a dependency such as:<\/span><\/p><p><span style=\"font-weight: 400;\">if (ready)<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0valid = 1&#8217;b1;<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">This may appear logical:<\/span><\/p><p><span style=\"font-weight: 400;\">&#8220;I will only say that I have data when the receiver says it is ready.&#8221;<\/span><\/p><p><span style=\"font-weight: 400;\">But it can create a deadlock.<\/span><\/p><p><span style=\"font-weight: 400;\">Imagine the receiver follows the opposite rule:<\/span><\/p><p><span style=\"font-weight: 400;\">&#8220;I will assert READY only after I see VALID.&#8221;<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">Now:<\/span><\/p><p><span style=\"font-weight: 400;\">Source waits for READY<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u2193<\/span><\/p><p><span style=\"font-weight: 400;\">Destination waits for VALID<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u2193<\/span><\/p><p><span style=\"font-weight: 400;\">Neither signal changes<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u2193<\/span><\/p><p><span style=\"font-weight: 400;\">Deadlock<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">The source should therefore be able to assert <\/span><span style=\"font-weight: 400;\">valid<\/span><span style=\"font-weight: 400;\"> independently when it has a transaction to send.<\/span><\/p><p><span style=\"font-weight: 400;\">The destination can assert <\/span><span style=\"font-weight: 400;\">ready<\/span><span style=\"font-weight: 400;\"> independently when it has capacity.<\/span><\/p><p><span style=\"font-weight: 400;\">This independence is one of the fundamental rules of a robust ready-valid interface.<\/span><\/p><p>\u00a0<\/p><h3><span style=\"font-weight: 400;\">Avoid Combinational Loops Between Modules<\/span><\/h3><p><span style=\"font-weight: 400;\">Another important design problem occurs when <\/span><span style=\"font-weight: 400;\">valid<\/span><span style=\"font-weight: 400;\"> and <\/span><span style=\"font-weight: 400;\">ready<\/span><span style=\"font-weight: 400;\"> are allowed to depend directly on each other through combinational logic.<\/span><\/p><p><span style=\"font-weight: 400;\">For example:<\/span><\/p><p><span style=\"font-weight: 400;\">Module A<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0VALID \u2500\u2500\u2500\u2500\u2500\u25ba Module B<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u25b2\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u2502<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u2502\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u25bc<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u2514\u2500\u2500\u2500\u2500 READY \u2500\u2518<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">If Module A&#8217;s <\/span><span style=\"font-weight: 400;\">valid<\/span><span style=\"font-weight: 400;\"> depends on Module B&#8217;s <\/span><span style=\"font-weight: 400;\">ready<\/span><span style=\"font-weight: 400;\">, while Module B&#8217;s <\/span><span style=\"font-weight: 400;\">ready<\/span><span style=\"font-weight: 400;\"> depends on Module A&#8217;s <\/span><span style=\"font-weight: 400;\">valid<\/span><span style=\"font-weight: 400;\">, a combinational loop can be created.<\/span><\/p><p><span style=\"font-weight: 400;\">This can cause:<\/span><\/p><ul><li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">synthesis problems<\/span><\/li><li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">timing problems<\/span><\/li><li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">unstable behavior<\/span><\/li><li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">difficult timing closure<\/span><\/li><li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">unexpected simulation behavior<\/span><\/li><\/ul><p><span style=\"font-weight: 400;\">A safer architecture uses registered state or carefully structured control logic to break such paths. Ready\/valid design references specifically identify combinational loops between source and destination control as a common pitfall.<\/span><\/p><p><span style=\"font-weight: 400;\">This becomes particularly important when several ready-valid interfaces are connected together in a pipeline.<\/span><\/p><p>\u00a0<\/p><h3><span style=\"font-weight: 400;\">Backpressure Is Part of the Handshake<\/span><\/h3><p><span style=\"font-weight: 400;\">Backpressure is simply the receiver&#8217;s ability to tell the sender:<\/span><\/p><p><span style=\"font-weight: 400;\">&#8220;Do not send the next transaction yet.&#8221;<\/span><\/p><p><span style=\"font-weight: 400;\">For example:<\/span><\/p><p><span style=\"font-weight: 400;\">Producer \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Consumer<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">VALID = 1\u00a0 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25ba<\/span><\/p><p><span style=\"font-weight: 400;\">DATA \u00a0 \u00a0 \u00a0 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25ba<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0READY = 0<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u2193<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Consumer busy<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">The producer must wait.<\/span><\/p><p><span style=\"font-weight: 400;\">Once the consumer becomes available:<\/span><\/p><p><span style=\"font-weight: 400;\">VALID = 1<\/span><\/p><p><span style=\"font-weight: 400;\">READY = 1<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">the transaction completes.<\/span><\/p><p><span style=\"font-weight: 400;\">This mechanism allows modules with different processing rates to work together.<\/span><\/p><p><span style=\"font-weight: 400;\">Backpressure is particularly important in:<\/span><\/p><ul><li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">pipelined RTL<\/span><\/li><li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">packet processing<\/span><\/li><li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">DMA engines<\/span><\/li><li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">FIFOs<\/span><\/li><li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">AXI-stream interfaces<\/span><\/li><li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">accelerators<\/span><\/li><li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">SoC interconnects<\/span><\/li><li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">streaming datapaths<\/span><\/li><\/ul><p><span style=\"font-weight: 400;\">Modern RTL pipelines commonly use ready-valid handshaking to control whether a pipeline stage can accept and forward data.<\/span><\/p><p>\u00a0<\/p><h3><span style=\"font-weight: 400;\">Why a Buffer May Be Necessary<\/span><\/h3><p><span style=\"font-weight: 400;\">Suppose a source has valid data but the destination suddenly becomes unavailable.<\/span><\/p><p><span style=\"font-weight: 400;\">If the source cannot hold the data internally, the design needs a storage element such as:<\/span><\/p><ul><li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">register<\/span><\/li><li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">skid buffer<\/span><\/li><li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">FIFO<\/span><\/li><\/ul><p><span style=\"font-weight: 400;\">A one-entry buffer can be enough for simple interfaces.<\/span><\/p><p><span style=\"font-weight: 400;\">Conceptually:<\/span><\/p><p><span style=\"font-weight: 400;\">Source<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u2502<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u25bc<\/span><\/p><p><span style=\"font-weight: 400;\">\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510<\/span><\/p><p><span style=\"font-weight: 400;\">\u2502 Data Buffer\u00a0 \u2502<\/span><\/p><p><span style=\"font-weight: 400;\">\u2502 Valid State\u00a0 \u2502<\/span><\/p><p><span style=\"font-weight: 400;\">\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u2502<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u25bc<\/span><\/p><p><span style=\"font-weight: 400;\">Destination<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">The buffer stores the transaction while the downstream module is stalled.<\/span><\/p><p><span style=\"font-weight: 400;\">This is one reason handshake-aware pipeline registers and skid buffers are common in high-performance RTL.<\/span><\/p><p>\u00a0<\/p><h3><span style=\"font-weight: 400;\">Request-Acknowledge Handshake<\/span><\/h3><p><span style=\"font-weight: 400;\">Ready-valid is not the only handshake method.<\/span><\/p><p><span style=\"font-weight: 400;\">For control transfers, particularly when communicating between different clock domains, a <\/span><b>request-acknowledge handshake<\/b><span style=\"font-weight: 400;\"> may be more appropriate.<\/span><\/p><p><span style=\"font-weight: 400;\">The basic sequence is:<\/span><\/p><p><span style=\"font-weight: 400;\">Source\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Destination<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">REQ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25ba<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Data transfer<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">ACK \u25c4\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">The source asserts <\/span><span style=\"font-weight: 400;\">REQ<\/span><span style=\"font-weight: 400;\"> and keeps the associated data stable.<\/span><\/p><p><span style=\"font-weight: 400;\">The destination detects the request, captures the data, and returns <\/span><span style=\"font-weight: 400;\">ACK<\/span><span style=\"font-weight: 400;\">.<\/span><\/p><p><span style=\"font-weight: 400;\">The source can then complete the transaction.<\/span><\/p><p><span style=\"font-weight: 400;\">A request-acknowledge protocol is particularly useful when data transfers are relatively infrequent and the additional latency is acceptable. It can also be used as part of a clock-domain-crossing architecture, provided the handshake control signals are synchronized appropriately.<\/span><\/p><p><span style=\"font-weight: 400;\">This is different from simply connecting a ready-valid interface across unrelated clocks.<\/span><\/p><p>\u00a0<\/p><h3><span style=\"font-weight: 400;\">Handshake Logic Across Clock Domains Needs Extra Care<\/span><\/h3><p><span style=\"font-weight: 400;\">A critical distinction is whether both RTL modules use the same clock.<\/span><\/p><p><span style=\"font-weight: 400;\">For a same-clock design:<\/span><\/p><p><span style=\"font-weight: 400;\">Module A \u2500\u2500\u2500\u2500\u2500\u25ba Module B<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0clk<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">a synchronous ready-valid handshake may be sufficient.<\/span><\/p><p><span style=\"font-weight: 400;\">For different clocks:<\/span><\/p><p><span style=\"font-weight: 400;\">Module A \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Module B<\/span><\/p><p><span style=\"font-weight: 400;\">clk_A\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 clk_B<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0REQ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25ba<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0ACK \u25c4\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">the control signals cross clock domains.<\/span><\/p><p><span style=\"font-weight: 400;\">A raw asynchronous control signal should not simply be sampled by the other domain.<\/span><\/p><p><a href=\"https:\/\/inskill.in\/training\/lint-cdc\/\"><span style=\"font-weight: 400;\">CDC techniques<\/span><\/a><span style=\"font-weight: 400;\"> such as synchronizers, request-acknowledge protocols, toggle synchronizers, or asynchronous FIFOs may be appropriate depending on the data rate and transfer requirements.<\/span><\/p><p><span style=\"font-weight: 400;\">For multi-bit data, the design must also ensure that the destination does not capture a changing or partially synchronized bus. In a request-acknowledge CDC design, one common strategy is for the source to hold the data stable for the duration of the handshake.<\/span><\/p><p>\u00a0<\/p><h3><span style=\"font-weight: 400;\">Common Handshake Design Mistakes<\/span><\/h3><h5><span style=\"font-weight: 400;\">1. Dropping VALID Too Early<\/span><\/h5><p><span style=\"font-weight: 400;\">Incorrect behavior:<\/span><\/p><p><span style=\"font-weight: 400;\">VALID = 1<\/span><\/p><p><span style=\"font-weight: 400;\">READY = 0<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">VALID = 0\u00a0 \u2190 transaction disappears<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">The transaction has not completed.<\/span><\/p><p><span style=\"font-weight: 400;\">The source should continue presenting it.<\/span><\/p><h5><span style=\"font-weight: 400;\">2. Changing DATA While VALID Is Waiting<\/span><\/h5><p><span style=\"font-weight: 400;\">If:<\/span><\/p><p><span style=\"font-weight: 400;\">VALID = 1<\/span><\/p><p><span style=\"font-weight: 400;\">READY = 0<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">the source should not replace the data with another transaction.<\/span><\/p><p><span style=\"font-weight: 400;\">Otherwise, the receiver may capture the wrong value when <\/span><span style=\"font-weight: 400;\">READY<\/span><span style=\"font-weight: 400;\"> eventually becomes high.<\/span><\/p><h5><span style=\"font-weight: 400;\">3. Making VALID Dependent on READY<\/span><\/h5><p><span style=\"font-weight: 400;\">This can create deadlock when the destination also waits for <\/span><span style=\"font-weight: 400;\">VALID<\/span><span style=\"font-weight: 400;\">.<\/span><\/p><h5><span style=\"font-weight: 400;\">4. Creating Combinational READY\/VALID Loops<\/span><\/h5><p><span style=\"font-weight: 400;\">Always inspect the control path between connected modules.<\/span><\/p><h5><span style=\"font-weight: 400;\">5. Forgetting Backpressure<\/span><\/h5><p><span style=\"font-weight: 400;\">A source that continuously generates data must have a strategy for what happens when the destination stalls.<\/span><\/p><h5><span style=\"font-weight: 400;\">6. Treating a CDC Handshake Like a Same-Clock Handshake<\/span><\/h5><p><span style=\"font-weight: 400;\">A ready-valid interface does not automatically make crossing unrelated clock domains safe.<\/span><\/p><p><span style=\"font-weight: 400;\">CDC synchronization requirements still apply.<\/span><\/p><h5><span style=\"font-weight: 400;\">7. Ignoring Reset Behavior<\/span><\/h5><p><span style=\"font-weight: 400;\">The interface should define what happens to <\/span><span style=\"font-weight: 400;\">valid<\/span><span style=\"font-weight: 400;\">, <\/span><span style=\"font-weight: 400;\">ready<\/span><span style=\"font-weight: 400;\">, pending data, and handshake state during reset.<\/span><\/p><p>\u00a0<\/p><h3><span style=\"font-weight: 400;\">Verifying Handshake Logic<\/span><\/h3><p><span style=\"font-weight: 400;\">Handshake logic should not be tested only with the ideal case where the receiver is always ready.<\/span><\/p><p><span style=\"font-weight: 400;\">A good testbench should deliberately introduce stalls.<\/span><\/p><p><span style=\"font-weight: 400;\">For example:<\/span><\/p><p><span style=\"font-weight: 400;\">Test 1:<\/span><\/p><p><span style=\"font-weight: 400;\">VALID = 1<\/span><\/p><p><span style=\"font-weight: 400;\">READY = 1<\/span><\/p><p><span style=\"font-weight: 400;\">\u2192 Transfer should occur<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">Test 2:<\/span><\/p><p><span style=\"font-weight: 400;\">VALID = 1<\/span><\/p><p><span style=\"font-weight: 400;\">READY = 0<\/span><\/p><p><span style=\"font-weight: 400;\">\u2192 Data must remain stable<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">Test 3:<\/span><\/p><p><span style=\"font-weight: 400;\">VALID = 0<\/span><\/p><p><span style=\"font-weight: 400;\">READY = 1<\/span><\/p><p><span style=\"font-weight: 400;\">\u2192 No transfer<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">Test 4:<\/span><\/p><p><span style=\"font-weight: 400;\">READY changes from 0 to 1<\/span><\/p><p><span style=\"font-weight: 400;\">\u2192 Pending transaction should transfer<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">Test 5:<\/span><\/p><p><span style=\"font-weight: 400;\">Receiver repeatedly stalls<\/span><\/p><p><span style=\"font-weight: 400;\">\u2192 No transaction should be lost<\/span><\/p><p>\u00a0<\/p><p><a href=\"https:\/\/inskill.in\/training\/sv-essentials\/\"><span style=\"font-weight: 400;\">SystemVerilog<\/span><\/a><span style=\"font-weight: 400;\"> Assertions can make these protocol rules easier to verify. For example, a useful property is that when <\/span><span style=\"font-weight: 400;\">valid<\/span><span style=\"font-weight: 400;\"> is asserted while <\/span><span style=\"font-weight: 400;\">ready<\/span><span style=\"font-weight: 400;\"> is low, the source continues to hold <\/span><span style=\"font-weight: 400;\">valid<\/span><span style=\"font-weight: 400;\"> and the data stable until the transfer occurs. Such protocol assertions are commonly used to catch handshake violations.<\/span><\/p><p><span style=\"font-weight: 400;\">A conceptual assertion is:<\/span><\/p><p><span style=\"font-weight: 400;\">property hold_valid_data;<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0@(posedge clk)<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0valid &amp;&amp; !ready |=&gt; valid &amp;&amp; $stable(data);<\/span><\/p><p><span style=\"font-weight: 400;\">endproperty<\/span><\/p><p>\u00a0<\/p><p><span style=\"font-weight: 400;\">The exact assertion should be adapted to the interface specification and reset behavior.<\/span><\/p><h3><span style=\"font-weight: 400;\">Ready-Valid vs Request-Acknowledge<\/span><\/h3><p><span style=\"font-weight: 400;\">The two approaches solve related but different problems.<\/span><\/p><table><tbody><tr><td><p><b>Feature<\/b><\/p><\/td><td><p><b>Ready-Valid<\/b><\/p><\/td><td><p><b>Request-Acknowledge<\/b><\/p><\/td><\/tr><tr><td><p><span style=\"font-weight: 400;\">Common use<\/span><\/p><\/td><td><p><span style=\"font-weight: 400;\">Streaming data<\/span><\/p><\/td><td><p><span style=\"font-weight: 400;\">Control\/data transaction<\/span><\/p><\/td><\/tr><tr><td><p><span style=\"font-weight: 400;\">Typical signals<\/span><\/p><\/td><td><p><span style=\"font-weight: 400;\">valid<\/span><span style=\"font-weight: 400;\">, <\/span><span style=\"font-weight: 400;\">ready<\/span><span style=\"font-weight: 400;\">, <\/span><span style=\"font-weight: 400;\">data<\/span><\/p><\/td><td><p><span style=\"font-weight: 400;\">req<\/span><span style=\"font-weight: 400;\">, <\/span><span style=\"font-weight: 400;\">ack<\/span><span style=\"font-weight: 400;\">, data<\/span><\/p><\/td><\/tr><tr><td><p><span style=\"font-weight: 400;\">Same-clock use<\/span><\/p><\/td><td><p><span style=\"font-weight: 400;\">Very common<\/span><\/p><\/td><td><p><span style=\"font-weight: 400;\">Common<\/span><\/p><\/td><\/tr><tr><td><p><span style=\"font-weight: 400;\">Backpressure<\/span><\/p><\/td><td><p><span style=\"font-weight: 400;\">Natural<\/span><\/p><\/td><td><p><span style=\"font-weight: 400;\">Usually explicit<\/span><\/p><\/td><\/tr><tr><td><p><span style=\"font-weight: 400;\">High throughput<\/span><\/p><\/td><td><p><span style=\"font-weight: 400;\">Excellent<\/span><\/p><\/td><td><p><span style=\"font-weight: 400;\">Lower<\/span><\/p><\/td><\/tr><tr><td><p><span style=\"font-weight: 400;\">CDC use<\/span><\/p><\/td><td><p><span style=\"font-weight: 400;\">Requires CDC architecture<\/span><\/p><\/td><td><p><span style=\"font-weight: 400;\">Common for low-rate CDC<\/span><\/p><\/td><\/tr><tr><td><p><span style=\"font-weight: 400;\">Typical applications<\/span><\/p><\/td><td><p><span style=\"font-weight: 400;\">Pipelines, streams, AXI<\/span><\/p><\/td><td><p><span style=\"font-weight: 400;\">Control transfers, CDC<\/span><\/p><\/td><\/tr><\/tbody><\/table><p><span style=\"font-weight: 400;\">The protocol should therefore be selected based on the architecture rather than simply choosing whichever interface has fewer signals.<\/span><\/p><p>\u00a0<\/p><h4><span style=\"font-weight: 400;\">Final Thoughts<\/span><\/h4><p><span style=\"font-weight: 400;\">Safe handshake logic is one of those RTL topics that looks simple until a design has to deal with stalls, backpressure, buffering, multiple pipeline stages, or different clock domains.<\/span><\/p><p><span style=\"font-weight: 400;\">The fundamental ready-valid rule is straightforward:<\/span><\/p><p><b>A transaction occurs when <\/b><b>VALID<\/b><b> and <\/b><b>READY<\/b><b> are both high on the active clock edge.<\/b><\/p><p><span style=\"font-weight: 400;\">The challenge is maintaining the rules around that transaction.<\/span><\/p><p><span style=\"font-weight: 400;\">The source must not lose or change a pending transaction simply because the destination is busy. <\/span><span style=\"font-weight: 400;\">VALID<\/span><span style=\"font-weight: 400;\"> should not wait for <\/span><span style=\"font-weight: 400;\">READY<\/span><span style=\"font-weight: 400;\">, and the connected modules should not create combinational loops through their handshake signals. For higher-throughput designs, buffering and carefully designed pipeline stages may be necessary. For clock-domain crossings, additional synchronization techniques are required.<\/span><\/p><p><span style=\"font-weight: 400;\">Once these principles are understood, handshake logic becomes a reusable design pattern rather than a collection of ad-hoc control signals.<\/span><\/p><p><span style=\"font-weight: 400;\">For RTL engineers, mastering handshake protocols is especially valuable because the same ideas appear repeatedly in pipelines, FIFOs, streaming interfaces, SoC integration, AXI-based systems, and CDC architectures. Ready-valid handshaking is also a common concept in <\/span><a href=\"https:\/\/inskill.in\/training\/rtl-integration-training\/\"><span style=\"font-weight: 400;\">RTL design<\/span><\/a><span style=\"font-weight: 400;\"> interviews, making it a useful topic to understand from both a design and verification perspective.<\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Modern RTL designs rarely consist of one block doing everything. A typical SoC or digital system is divided into multiple modules, with each block responsible for a specific operation. One module may generate data, another may process it, and a third may store or forward the result. The difficult part is not simply connecting these modules with wires. The receiving module may be busy when data arrives, while the transmitting module may not have data available on every clock cycle. Without proper control logic, this can lead to lost data, duplicated transactions, overwritten values, or modules waiting indefinitely for each other. This is where handshake logic becomes important. A handshake provides an agreed mechanism for two RTL modules to communicate. The most common approach for synchronous data transfer is the ready-valid handshake, where the source indicates that data is available using valid and the destination indicates that it can accept the data using ready. A transfer takes place when both signals are high at the active clock edge. For some control or clock-domain-crossing applications, a request-acknowledge handshake is more appropriate. The important point is that a handshake is not just two control signals. It is a protocol with rules that both sides must follow. Why Is Handshake Logic Needed in RTL? Consider two synchronous modules: \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Data Module A \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25ba Module B \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Control \u00a0 Module A produces data, while Module B consumes it. Suppose Module A produces a new value every clock cycle, but Module B needs two cycles to process each value. If Module A continues sending data without knowing whether Module B can accept it, some values may be overwritten or lost. A handshake solves this problem by allowing the receiver to apply backpressure. The source effectively says: &#8220;I have valid data available.&#8221; The destination responds: &#8220;I am ready to accept it.&#8221; Only when both conditions are true does the transfer occur. This approach allows independently designed RTL modules to communicate without assuming that both sides operate at exactly the same processing rate. \u00a0 Ready-Valid Handshake: The Most Common RTL Approach A basic ready-valid interface contains three signals: valid ready data \u00a0 The source drives valid and data. The destination drives ready. The fundamental transfer condition is: assign transfer = valid &amp;&amp; ready; \u00a0 At a rising clock edge: valid = 0, ready = 0 \u2192 No transfer valid = 0, ready = 1 \u2192 No transfer valid = 1, ready = 0 \u2192 No transfer valid = 1, ready = 1 \u2192 Transfer \u00a0 This behavior is also used extensively in industry-standard streaming interfaces. AMD documentation, for example, defines a valid transfer when READY and VALID are asserted at the rising clock edge. A useful way to remember the protocol is: VALID means &#8220;the source has something to transfer.&#8221; READY means &#8220;the destination can accept it.&#8221; VALID &amp;&amp; READY means &#8220;the transfer happens now.&#8221; \u00a0 The Source Must Hold Data When the Receiver Is Not Ready One of the most important rules is what happens when: valid = 1 ready = 0 \u00a0 The source cannot assume that the transaction has completed. Instead, it must keep the transaction available until the destination accepts it. For example: always_ff @(posedge clk) begin \u00a0\u00a0\u00a0\u00a0if (reset) begin \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0valid &lt;= 1&#8217;b0; \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0data\u00a0 &lt;= &#8216;0; \u00a0\u00a0\u00a0\u00a0end \u00a0\u00a0\u00a0\u00a0else if (valid &amp;&amp; ready) begin \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0valid &lt;= 1&#8217;b0; \u00a0\u00a0\u00a0\u00a0end \u00a0\u00a0\u00a0\u00a0else if (new_data) begin \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0data\u00a0 &lt;= input_data; \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0valid &lt;= 1&#8217;b1; \u00a0\u00a0\u00a0\u00a0end end \u00a0 The exact implementation will depend on the surrounding architecture, but the principle is critical: Once a source presents a valid transaction, it must not change the transaction simply because the destination is temporarily unable to accept it. Ready\/valid references similarly emphasize that data and valid must remain stable while the source is waiting for ready. This prevents the receiver from sampling one value while the source has already moved to another. \u00a0 A Simple RTL Handshake Example Suppose one module sends an 8-bit value to another module. The interface could be: module producer ( \u00a0\u00a0\u00a0\u00a0input\u00a0 logic \u00a0 \u00a0 \u00a0 clk, \u00a0\u00a0\u00a0\u00a0input\u00a0 logic \u00a0 \u00a0 \u00a0 rst_n, \u00a0\u00a0\u00a0\u00a0input\u00a0 logic \u00a0 \u00a0 \u00a0 start, \u00a0\u00a0\u00a0\u00a0input\u00a0 logic [7:0] input_data, \u00a0 \u00a0\u00a0\u00a0\u00a0output logic \u00a0 \u00a0 \u00a0 valid, \u00a0\u00a0\u00a0\u00a0output logic [7:0] data, \u00a0\u00a0\u00a0\u00a0input\u00a0 logic \u00a0 \u00a0 \u00a0 ready ); \u00a0 The basic transfer event is: wire transfer; \u00a0 assign transfer = valid &amp;&amp; ready; \u00a0 The producer can capture the data and assert valid: always_ff @(posedge clk or negedge rst_n) begin \u00a0\u00a0\u00a0\u00a0if (!rst_n) begin \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0valid &lt;= 1&#8217;b0; \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0data\u00a0 &lt;= 8&#8217;d0; \u00a0\u00a0\u00a0\u00a0end \u00a0\u00a0\u00a0\u00a0else begin \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if (start &amp;&amp; !valid) begin \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0data\u00a0 &lt;= input_data; \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0valid &lt;= 1&#8217;b1; \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0end \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0else if (transfer) begin \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0valid &lt;= 1&#8217;b0; \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0end \u00a0\u00a0\u00a0\u00a0end end \u00a0 The receiving module can indicate that it is able to accept data: assign ready = !busy; \u00a0 The actual implementation may be more complex, but the fundamental relationship remains the same. \u00a0 Never Make VALID Wait for READY One of the most common handshake mistakes is creating a dependency such as: if (ready) \u00a0\u00a0\u00a0\u00a0valid = 1&#8217;b1; \u00a0 This may appear logical: &#8220;I will only say that I have data when the receiver says it is ready.&#8221; But it can create a deadlock. Imagine the receiver follows the opposite rule: &#8220;I will assert READY only after I see VALID.&#8221; \u00a0 Now: Source waits for READY \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u2193 Destination waits for VALID \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u2193 Neither signal changes \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u2193 Deadlock \u00a0 The source should therefore be able to assert valid independently when it has a transaction to send. The destination can assert ready independently when it has capacity. This independence is one of the fundamental rules of a robust ready-valid interface. \u00a0 Avoid Combinational Loops Between Modules Another important design problem occurs when valid and ready are allowed to depend directly on each other through combinational logic. For example: Module A \u00a0\u00a0VALID \u2500\u2500\u2500\u2500\u2500\u25ba Module B \u00a0\u00a0\u00a0\u00a0\u00a0\u25b2\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u2502 \u00a0\u00a0\u00a0\u00a0\u00a0\u2502\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u25bc \u00a0\u00a0\u00a0\u00a0\u00a0\u2514\u2500\u2500\u2500\u2500 READY \u2500\u2518 \u00a0 If Module A&#8217;s valid depends on Module B&#8217;s ready, while Module B&#8217;s ready depends on Module A&#8217;s valid, a combinational loop can be created.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_hide_featured_image":false,"_jetpack_featured_image_duplicate_dismissed":0,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[8],"tags":[],"class_list":["post-10126","post","type-post","status-publish","format-standard","hentry","category-vlsi"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.8 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>How to Design Safe Handshake Logic Between RTL Modules<\/title>\n<meta name=\"description\" content=\"Learn how to design safe handshake logic between RTL modules using ready-valid and request-acknowledge protocols, with Verilog examples and common RTL mistakes.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/inskill.in\/training\/blog\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to Design Safe Handshake Logic Between RTL Modules\" \/>\n<meta property=\"og:description\" content=\"Learn how to design safe handshake logic between RTL modules using ready-valid and request-acknowledge protocols, with Verilog examples and common RTL mistakes.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/inskill.in\/training\/blog\/\" \/>\n<meta property=\"og:site_name\" content=\"Inskill VLSIGURU Elearning Platform\" \/>\n<meta property=\"article:published_time\" content=\"2026-09-02T06:03:28+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-09-15T06:06:22+00:00\" \/>\n<meta name=\"author\" content=\"admin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"admin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/inskill.in\\\/training\\\/blog\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/inskill.in\\\/training\\\/blog\\\/\"},\"author\":{\"name\":\"admin\",\"@id\":\"https:\\\/\\\/inskill.in\\\/training\\\/#\\\/schema\\\/person\\\/9abb65edd31606e6675ad9c153f2d42f\"},\"headline\":\"How to Design Safe Handshake Logic Between RTL Modules\",\"datePublished\":\"2026-09-02T06:03:28+00:00\",\"dateModified\":\"2026-09-15T06:06:22+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/inskill.in\\\/training\\\/blog\\\/\"},\"wordCount\":1984,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/inskill.in\\\/training\\\/#organization\"},\"articleSection\":[\"VLSI\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/inskill.in\\\/training\\\/blog\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/inskill.in\\\/training\\\/blog\\\/\",\"url\":\"https:\\\/\\\/inskill.in\\\/training\\\/blog\\\/\",\"name\":\"How to Design Safe Handshake Logic Between RTL Modules\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/inskill.in\\\/training\\\/#website\"},\"datePublished\":\"2026-09-02T06:03:28+00:00\",\"dateModified\":\"2026-09-15T06:06:22+00:00\",\"description\":\"Learn how to design safe handshake logic between RTL modules using ready-valid and request-acknowledge protocols, with Verilog examples and common RTL mistakes.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/inskill.in\\\/training\\\/blog\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/inskill.in\\\/training\\\/blog\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/inskill.in\\\/training\\\/blog\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/inskill.in\\\/training\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to Design Safe Handshake Logic Between RTL Modules\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/inskill.in\\\/training\\\/#website\",\"url\":\"https:\\\/\\\/inskill.in\\\/training\\\/\",\"name\":\"Inskill VLSIGURU Elearning Platform\",\"description\":\"Best VLSI Training Institute\",\"publisher\":{\"@id\":\"https:\\\/\\\/inskill.in\\\/training\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/inskill.in\\\/training\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/inskill.in\\\/training\\\/#organization\",\"name\":\"Inskill VLSIGURU Elearning Platform\",\"url\":\"https:\\\/\\\/inskill.in\\\/training\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/inskill.in\\\/training\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/inskill.in\\\/training\\\/wp-content\\\/uploads\\\/2025\\\/01\\\/inskill-2.png\",\"contentUrl\":\"https:\\\/\\\/inskill.in\\\/training\\\/wp-content\\\/uploads\\\/2025\\\/01\\\/inskill-2.png\",\"width\":207,\"height\":89,\"caption\":\"Inskill VLSIGURU Elearning Platform\"},\"image\":{\"@id\":\"https:\\\/\\\/inskill.in\\\/training\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/inskill.in\\\/training\\\/#\\\/schema\\\/person\\\/9abb65edd31606e6675ad9c153f2d42f\",\"name\":\"admin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/ae1b84b5e32e75453917297a43292af55fcc34a59a0d20dc5403287472a37c28?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/ae1b84b5e32e75453917297a43292af55fcc34a59a0d20dc5403287472a37c28?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/ae1b84b5e32e75453917297a43292af55fcc34a59a0d20dc5403287472a37c28?s=96&d=mm&r=g\",\"caption\":\"admin\"},\"sameAs\":[\"https:\\\/\\\/inskill.in\\\/training\"],\"url\":\"https:\\\/\\\/inskill.in\\\/training\\\/author\\\/admin\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"How to Design Safe Handshake Logic Between RTL Modules","description":"Learn how to design safe handshake logic between RTL modules using ready-valid and request-acknowledge protocols, with Verilog examples and common RTL mistakes.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/inskill.in\/training\/blog\/","og_locale":"en_US","og_type":"article","og_title":"How to Design Safe Handshake Logic Between RTL Modules","og_description":"Learn how to design safe handshake logic between RTL modules using ready-valid and request-acknowledge protocols, with Verilog examples and common RTL mistakes.","og_url":"https:\/\/inskill.in\/training\/blog\/","og_site_name":"Inskill VLSIGURU Elearning Platform","article_published_time":"2026-09-02T06:03:28+00:00","article_modified_time":"2026-09-15T06:06:22+00:00","author":"admin","twitter_card":"summary_large_image","twitter_misc":{"Written by":"admin","Est. reading time":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/inskill.in\/training\/blog\/#article","isPartOf":{"@id":"https:\/\/inskill.in\/training\/blog\/"},"author":{"name":"admin","@id":"https:\/\/inskill.in\/training\/#\/schema\/person\/9abb65edd31606e6675ad9c153f2d42f"},"headline":"How to Design Safe Handshake Logic Between RTL Modules","datePublished":"2026-09-02T06:03:28+00:00","dateModified":"2026-09-15T06:06:22+00:00","mainEntityOfPage":{"@id":"https:\/\/inskill.in\/training\/blog\/"},"wordCount":1984,"commentCount":0,"publisher":{"@id":"https:\/\/inskill.in\/training\/#organization"},"articleSection":["VLSI"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/inskill.in\/training\/blog\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/inskill.in\/training\/blog\/","url":"https:\/\/inskill.in\/training\/blog\/","name":"How to Design Safe Handshake Logic Between RTL Modules","isPartOf":{"@id":"https:\/\/inskill.in\/training\/#website"},"datePublished":"2026-09-02T06:03:28+00:00","dateModified":"2026-09-15T06:06:22+00:00","description":"Learn how to design safe handshake logic between RTL modules using ready-valid and request-acknowledge protocols, with Verilog examples and common RTL mistakes.","breadcrumb":{"@id":"https:\/\/inskill.in\/training\/blog\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/inskill.in\/training\/blog\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/inskill.in\/training\/blog\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/inskill.in\/training\/"},{"@type":"ListItem","position":2,"name":"How to Design Safe Handshake Logic Between RTL Modules"}]},{"@type":"WebSite","@id":"https:\/\/inskill.in\/training\/#website","url":"https:\/\/inskill.in\/training\/","name":"Inskill VLSIGURU Elearning Platform","description":"Best VLSI Training Institute","publisher":{"@id":"https:\/\/inskill.in\/training\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/inskill.in\/training\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/inskill.in\/training\/#organization","name":"Inskill VLSIGURU Elearning Platform","url":"https:\/\/inskill.in\/training\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/inskill.in\/training\/#\/schema\/logo\/image\/","url":"https:\/\/inskill.in\/training\/wp-content\/uploads\/2025\/01\/inskill-2.png","contentUrl":"https:\/\/inskill.in\/training\/wp-content\/uploads\/2025\/01\/inskill-2.png","width":207,"height":89,"caption":"Inskill VLSIGURU Elearning Platform"},"image":{"@id":"https:\/\/inskill.in\/training\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/inskill.in\/training\/#\/schema\/person\/9abb65edd31606e6675ad9c153f2d42f","name":"admin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/ae1b84b5e32e75453917297a43292af55fcc34a59a0d20dc5403287472a37c28?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/ae1b84b5e32e75453917297a43292af55fcc34a59a0d20dc5403287472a37c28?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/ae1b84b5e32e75453917297a43292af55fcc34a59a0d20dc5403287472a37c28?s=96&d=mm&r=g","caption":"admin"},"sameAs":["https:\/\/inskill.in\/training"],"url":"https:\/\/inskill.in\/training\/author\/admin\/"}]}},"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/inskill.in\/training\/wp-json\/wp\/v2\/posts\/10126","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/inskill.in\/training\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/inskill.in\/training\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/inskill.in\/training\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/inskill.in\/training\/wp-json\/wp\/v2\/comments?post=10126"}],"version-history":[{"count":4,"href":"https:\/\/inskill.in\/training\/wp-json\/wp\/v2\/posts\/10126\/revisions"}],"predecessor-version":[{"id":10132,"href":"https:\/\/inskill.in\/training\/wp-json\/wp\/v2\/posts\/10126\/revisions\/10132"}],"wp:attachment":[{"href":"https:\/\/inskill.in\/training\/wp-json\/wp\/v2\/media?parent=10126"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/inskill.in\/training\/wp-json\/wp\/v2\/categories?post=10126"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/inskill.in\/training\/wp-json\/wp\/v2\/tags?post=10126"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}