数字电路valid-ready握手协议浅析(handshake protocol)

这篇具有很好参考价值的文章主要介绍了数字电路valid-ready握手协议浅析(handshake protocol)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

  1. 握手协议背景介绍


我第一次接触握手协议,是在一次fpga开发工程师实习面试中。当时面试官通过邮件给我发送了一个题目:实现对握手协议的打拍,要求传输无气泡。作为萌新的我只能查阅互联网。在使用该协议一段时间后,我总结了一些冠以该协议的知识点以及使用该协议时存在的一些问题,在此总结以便于看到此文章的读者使用握手协议设计自己的rtl代码。由于作者经验有限,如果文章有错误或者不理解之处,欢迎在评论中给我留言😊。

数字电路valid-ready握手协议浅析(handshake protocol)

握手协议是一种可以实现数据安全传输的协议,其适用于上下游模块之间的数据传输。其广泛应用于AXI总线以及流水线设计中。

对于上下游模块之间的数据传输,最简单的模式就是连接一个数据通道(data信号)。但是它存在两个致命问题:

  1. 下游模块并不知道在哪段时间内,该数据通道内的数据是有效的。

  1. 当下游模块发生阻塞时,无法反压上游,使得上游暂停数据的发送

为了解决上述问题,我们又引入了两个信号 : valid 和 ready 。 

当valid拉高时,代表该时间段内数据有效。

当ready拉低时,下游可以反压上游,使得其不再发送数据。

valid和ready就是两只大手,当这两只手握在一起时,就代表这一拍的数据安全从上游传递到了下游,因此,握手协议最重要的就是保证了数据的有效性和安全性。

数据安全性:在数据传输过程中,保证不会存在存在数据重复或者丢失的情况

module handshake_signal#(
    parameter data_width = 32
)(
    //上游数据输入接口
    input [data_width - 1 : 0]     din,
    input                          din_valid,
    output                         dout_ready,

    //下游数据输出接口
    output [data_width - 1 : 0]    dout,
    output                         dout_valid,
    input                          dout_ready
);

endmodule

  1. 握手协议的死锁情况


试想,当我们和别人握手时,如果双方都不主动伸出手,双方都在等待对方伸出手的话,那么我们和他人的握手就永远不会发生。同理,在我们设计rtl代码时,当我们上游的模块以ready作为数据发送的触发条件,而下游模块以valid作为数据接受的触发条件时,那么这两个模块之间就永远不会发送数据传送。这就是所谓的握手协议的死锁情况。

因此当我们设计rtl代码时,一定要规定好主动发起握手的一端,例如下游主动拉高ready信号或者上游主动拉高valid信号。同时也要避免间接的使用valid或ready进行判断而导致的组合逻辑回环问题。

在要使用fifo作为数据缓冲的总线中,我们也可以设计带有握手协议的fifo,该fifo的上游端口ready信号会主动拉高,而下游端口valid信号,会在当fifo内存在数据时主动拉高。这样设计的好处是我们可以在fifo上游和下游的数据处理模块中直接使用valid和ready作为判断条件,而不必关注总线握手发生死锁的情况。


  1. 握手协议的时序优化


由于握手协议经常使用在总线中,总线往往会有较高的信号扇出以及通过仲裁的情况。而一端总线的上下游数据处理模块也可能有较多的组合逻辑。因此对采用握手协议的总线进行时序优化是必要的。

当我们进行时序优化时,最常想到的就是在组合逻辑路径较长的地方插入寄存器,打断组合逻辑路径。在握手协议中,就是在valid,ready以及data这三个数据路径中插入寄存器。但是在插入寄存器后,valid和ready会由于寄存器而延迟一拍,这样可能会造成数据传输时,不能保证数据的安全性。因此我们分类讨论三种情况:

  1. 只对valid和data插入寄存器

module handshake_signal#(
    parameter data_width = 32
)(
    //时钟和复位信号
    input                          clk,
    input                          rst_n,

    //上游数据输入接口
    input [data_width - 1 : 0]     din,
    input                          din_valid,
    output                         dout_ready,

    //下游数据输出接口
    output [data_width - 1 : 0]    dout,
    output                         dout_valid,
    input                          dout_ready
);

reg [data_width - 1 : 0] data_reg;
reg                      valid_reg;

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        data_reg  <= 'b0;
        valid_reg <= 1'b0;
    end else begin
        data_reg  <= din;
        valid_reg <= din_valid;
    end
end

assign dout       = data_reg;
assign dout_valid = valid_reg;
assign din_ready  = dout_ready;


endmodule

出现错误的情况:如下图所示,如果ready没有拉高,此时数据上游保持原来数据不变。valid和data寄存器中保持一份上游数据。当下游ready拉高时,会先将打拍寄存器中的值读走。此时打拍寄存器会再保存一份上游数据,而上游数据接收到ready时,原先数据就不再保持了。再过一个时钟周期,下游会读取打拍寄存器中的值,而此刻打拍寄存器传递给下游的值还是上游的旧值。这个旧值被传递了两次。因此会导致下游接收数据的重复,从而无法保证数据传递的安全性。

数字电路valid-ready握手协议浅析(handshake protocol)

出现错误的时序图:

数字电路valid-ready握手协议浅析(handshake protocol)

总结: ready上升沿出现错误,上游数据重复一拍

  1. 只对ready插入寄存器

module handshake_signal#(
    parameter data_width = 32
)(
    //时钟和复位信号
    input                          clk,
    input                          rst_n,

    //上游数据输入接口
    input [data_width - 1 : 0]     din,
    input                          din_valid,
    output                         dout_ready,

    //下游数据输出接口
    output [data_width - 1 : 0]    dout,
    output                         dout_valid,
    input                          dout_ready
);

reg                      ready_reg;

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        ready_reg <= 1'b0;
    end else begin
        ready_reg <= dout_ready;
    end
end

assign dout       = din;
assign dout_valid = din_valid;
assign din_ready  = ready_reg;

endmodule

数据丢失的情况:

对ready信号插入寄存器后,由于寄存器延迟1个clock,会导致下游无法及时反压上游数据。上游向下游传递数据时,丢失1个clock的数据。

由下图所示,在clock0时:

数据上游模块行为:上游模块接收到ready0信号,此时上游模块满足握手条件(valid0,ready0),上游模块认为data0已经传递到下游模块,因此上游模块将data0切换为data1

数据下游模块行为:下游模块满足的握手条件(valid0,ready1),下游模块接收到data0。

在clock1时:

数据上游模块行为:上游模块接收到ready1信号,此时上游模块满足握手条件(valid1,ready1),

上游模块认为data1已经安全传输到下游,因此上游模块将传输数据切换为data2

数据下游模块行为:下游模块接收到上游的data1和valid1信号,但是此时下游模块没有ready信号,因此下游模块不满足握手条件,data1未存入下游模块中,因此data1丢失

在clock2时:

数据上游模块行为:上游模块不满足握手条件,因此上游模块保持data2数据不变

数据下游模块行为:下游模块不接收上游数据,也不发起ready

数字电路valid-ready握手协议浅析(handshake protocol)

总结 :ready下降沿出现错误,上游数据丢失一拍

出现错误的时序图:

数字电路valid-ready握手协议浅析(handshake protocol)

数据重复的情况:

对ready信号插入寄存器后,由于寄存器延迟1个clock,上游数据无法及时收到ready信号,会导致下游数据接收两次上游传递的数据。

由下图所示:

在clock0时:

数据上游模块行为:上游模块主动发起valid0和data0的传输。

数据下游模块行为:未准备好接收上游发送的数据。

在clock1时:

数据上游模块行为:未收到ready信号,因此继续保持data0和valid0

数据下游模块行为:下游开始接收数据,此时由于valid0和ready0有效,下游模块达成握手条件,data0被下游模块处理。

在clock2时:

数据上游模块行为:上游收到ready0信号,因此上游模块将传输数据切换为data1

数据下游模块行为:下游正常接收数据,此时由于valid0和ready1有效,下游模块达成握手条件,data0被下游模块处理,导致data0被重复处理两次。

数字电路valid-ready握手协议浅析(handshake protocol)

出现错误的时序图:

数字电路valid-ready握手协议浅析(handshake protocol)

总结:ready上升沿出现错误,上游数据重复一拍

  1. 对valid,data以及ready都插入寄存器

module handshake_signal#(
    parameter data_width = 32
)(
    //时钟和复位信号
    input                          clk,
    input                          rst_n,
    
    //上游数据输入接口
    input [data_width - 1 : 0]     din,
    input                          din_valid,
    output                         dout_ready,

    //下游数据输出接口
    output [data_width - 1 : 0]    dout,
    output                         dout_valid,
    input                          dout_ready
);

reg [data_width - 1 : 0] data_reg;
reg                      valid_reg;
reg                      ready_reg;

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        data_reg  <= 'b0;
        valid_reg <= 1'b0;
        ready_reg <= 1'b0;
    end else begin
        data_reg  <= din;
        valid_reg <= din_valid;
        ready_reg <= dout_ready;
    end
end

assign dout       = data_reg;
assign dout_valid = valid_reg;
assign din_ready  = ready_reg;

endmodule

是对以上两种情况的总和。即:ready的上升沿和下降沿都会出现错误,在ready上升沿时,数据丢失一拍,在ready下降沿时,上游数据丢失一拍

在对以上情况进行分析后,我们明确了数据重复以及丢失的情况。因此对于valid data 以及 ready信号进行简单打拍是无法保证数据传输的安全性的。因此我们需要对握手信号打拍进行特殊处理。

出现错误的时序图:

数字电路valid-ready握手协议浅析(handshake protocol)

解决方法:

使用带有握手信号的fifo。原因有两个:

  1. 在使用握手信号的fifo时,由于fifo内部的空慢判断是由指针控制的,而指针的增减会绝对准确的知道上游写入fifo数据的个数和下游读出fifo数据的个数。这样就不会出现数据重复或者丢失的情况

  1. 由于使用两个计数器来作为判断条件,主动发起上游ready或者下游valid,这两个计数器的本质也是寄存器。用计数器作为判断条件,我们就会将上下游的数据用寄存器隔离开。这样会有利于时序优化。

//此设计为深度为1的fifo,可以用作对握手信号的打拍
//可以在此设计的基础上进行适当的更改,加大fifo的深度
module sync_fifo#(
    parameter data_width = 32
)(
    //时钟和复位信号
    input                          clk,
    input                          rst_n,
    
    //上游数据输入接口
    input [data_width - 1 : 0]     din,
    input                          din_valid,
    output                         dout_ready,

    //下游数据输出接口
    output [data_width - 1 : 0]    dout,
    output                         dout_valid,
    input                          dout_ready
);

reg [data_width - 1 : 0] data_reg;
reg                      valid_reg;
reg                      ready_reg;

reg [1:0]                din_counter;
reg [1:0]                dout_counter;

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        din_counter <= 'b0;
    end else begin
        if(din_valid & din_ready)begin
            din_counter <= din_counter + 1'b1;
        end
    end
end

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        dout_counter <= 'b0;
    end else begin
        if(dout_valid & dout_ready)begin
            dout_counter <= dout_counter + 1'b1;
        end
    end
end


always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        data_reg     <= 'b0;
        valid_reg    <= 1'b0;
        ready_reg    <= 1'b0;
    end else begin
        if(din_counter[1] == dout_counter[1]) begin
            if(din_counter[0] > dout_counter[0]) begin
                ready_reg   <= 1'b0;
                data_reg    <= data_reg;
                valid_reg   <= valid_reg;
            end else begin
                ready_reg   <= 1'b1;
                data_reg    <= din;
                valid_reg   <= din_valid;
            end
        end else begin
            if(din_counter[0] < dout_counter[0]) begin
                ready_reg   <= 1'b0;
                data_reg    <= data_reg;
                valid_reg   <= valid_reg;
            end else begin
                ready_reg   <= 1'b1;
                data_reg    <= din;
                valid_reg   <= din_valid;
            end
        end
    end
end

assign dout       = data_reg;
assign dout_valid = valid_reg;
assign din_ready  = ready_reg;

endmodule

在使用skid buffer时,其本质也是一个深度为1的fifo,但是由于在设计时,有可能会用到下游的信号来判断上游的valid或ready状态,当出现判断时,其本质也是组合逻辑,会导致上下游信号直接进行组合逻辑连接。因此在使用该方法时,需要注意判断条件导致的组合逻辑路径过长

module skid_buffer #(
    parameter data_width = 64
)(
    //时钟和复位信号
    input                          clk,
    input                          rst_n,
    
    //上游数据输入接口
    input [data_width - 1 : 0]     din,
    input                          din_valid,
    output                         dout_ready,

    //下游数据输出接口
    output [data_width - 1 : 0]    dout,
    output                         dout_valid,
    input                          dout_ready
);

reg                      pre_dout_ready;
reg [data_width - 1 : 0] din_reg_0;
reg                      din_valid_reg_0;
reg                      dout_ready_reg_0;
reg [data_width - 1 : 0] din_reg_1;
reg                      din_valid_reg_1;

//未完待续...
endmodule

  1. 总结


在高速数字电路设计中,使用流水线加速数据的计算是一种很好的方法。而在流水线计算中,几乎一定要使用握手协议,作为流水线上下游模块的数据传输总线。

当我们使用握手协议的总线时,首先要明确该总线上下游的模块对于valid和ready处理的方式,是它主动发起valid或ready还是需要我们自己设计的模块主动发起valid和ready,以避免握手协议死锁情况的出现。同时,对于该类型总线进行时序优化,插入寄存器打拍时,一定要注意数据安全性,即数据是否丢失或者数据是否重复。

对于上述问题,插入一个握手协议的fifo或者使用skid buffer是一个很好的解决方法。


参考资料:

  1. https://zipcpu.com/blog/2019/05/22/skidbuffer.html

  1. https://zipcpu.com/blog/2021/08/28/axi-rules.html


WaveDrom Editor 代码段

  1. 对valid和data打拍的时序图:

{signal: [
  {    name: 'clk',   wave: 'PPPPPP'},
  ['上游数据端',
   {  name: 'din',          wave: '033400', data: 'data0 data0 data1 data1 data1'},
   {  name: 'din_valid',     wave: '011100', data: 'D1'   },
   {  name: 'din_ready',     wave: '001110', data: 'D1'   },
  ],
  {},
  ['中间寄存器',
   {  name: 'data_reg',      wave: '003340', data: 'data0 data0 data1'},
   {  name: 'valid_reg',     wave: '001110', data: 'D1'   },
//   {  name: 'ready_reg',     wave: '000100', data: 'D1'   },
  ],   
   
  {},
  ['下游数据端',
   {  name: 'dout',         wave: '003340', data: 'data0 data0 data1'},
   {  name: 'dout_valid',     wave: '001110', data: 'Q2'},
   {  name: 'dout_ready',     wave: '001110', data: 'Q2'},
  ]
]}
  1. 对ready打拍,ready上升沿时序图:

{signal: [
  {    name: 'clk',   wave: 'PPPPPP'},
  ['上游数据端',
   {  name: 'din',          wave: '033400', data: 'data0 data0 data1 data1 data1'},
   {  name: 'din_valid',     wave: '011100', data: 'D1'   },
   {  name: 'din_ready',     wave: '001110', data: 'D1'   },
  ],
  {},
  ['中间寄存器',
//   {  name: 'data_reg',      wave: '003340', data: 'data0 data0 data1'},
//   {  name: 'valid_reg',     wave: '001110', data: 'D1'   },
   {  name: 'ready_reg',     wave: '001110', data: 'D1'   },
  ],   
   
  {},
  ['下游数据端',
   {  name: 'dout',         wave: '033400', data: 'data0 data0 data1'},
   {  name: 'dout_valid',     wave: '011100', data: 'Q2'},
   {  name: 'dout_ready',     wave: '011100', data: 'Q2'},
  ]
]}
  1. 对ready打拍,ready下降沿时序图:文章来源地址https://www.toymoban.com/news/detail-471493.html

{signal: [
  {    name: 'clk',   wave: 'PPP'},
  ['上游数据端',
   {  name: 'din',          wave: '340', data: 'data0 data1'},
   {  name: 'din_valid',     wave: '110', data: 'D1'   },
   {  name: 'din_ready',     wave: '110', data: 'D1'   },
  ],
  {},
  ['中间寄存器',
//   {  name: 'data_reg',      wave: '003340', data: 'data0 data0 data1'},
//   {  name: 'valid_reg',     wave: '001110', data: 'D1'   },
   {  name: 'ready_reg',     wave: '110', data: 'D1'   },
  ],   
   
  {},
  ['下游数据端',
   {  name: 'dout',         wave: '340', data: 'data0 data1'},
   {  name: 'dout_valid',     wave: '110', data: 'Q2'},
   {  name: 'dout_ready',     wave: '100', data: 'Q2'},
  ]
]}

到了这里,关于数字电路valid-ready握手协议浅析(handshake protocol)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • TCP 三次握手&四次挥手浅析

    大家都知道传输层中的TCP协议是面向连接的,提供可靠的连接服务,其中最出名的就是三次握手和四次挥手。 三次握手的交互过程如下 喜欢钻牛角尖的我在学习三次握手的时候就想到了几个问题:为什么三次握手是三次?不是一次、两次或者更多?如果是两次或者是一次会

    2024年02月15日
    浏览(82)
  • 使用Wireshark浅析Tcp三次握手

    我不想 一开始直接搬网络描述图来讲三次握手亦或试图用大量专业词汇让你熟悉它,而是想用 简单的描述 ,让大家对 三次握手 有个大概的印象。用 Wireshark 抓包工具分析TCP报文中大家比较关注的syn(Synchronize Sequence Numbers 同步序列号)和ack(ACKnowledge Character 确认字符)。 如果你

    2024年02月08日
    浏览(63)
  • SSL握手协议相关概念

     下图为握手协议的流程图,具体的解释参考博客: 【下】安全HTTPS-全面详解对称加密,非对称加密,数字签名,数字证书和HTTPS_tenfyguo的博客-CSDN博客  下面梳理一下SSL协议中的一些细节。首先是相关名词:证书、签名、非对称加密、预主秘钥。 非对称加密是一类加密算法

    2024年02月13日
    浏览(32)
  • TCP协议握手挥手

    三次握手可以确保连接建立 客户端向服务器发送连接请求,等待服务器确认 服务器向客户端返回一个响应,告诉客户端收到请求了 客户端再次发送确认消息,确认收到允许连接的响应消息,连接建立 以上三次握手主要确认连接建立 主要确保连接断开,并且数据处理完毕 客

    2024年02月12日
    浏览(24)
  • 数字IC手撕代码-流水握手(利用握手解决流水线断流、反压问题)

     前言:         本专栏旨在记录高频笔面试手撕代码题,以备数字前端秋招,本专栏所有文章提供原理分析、代码及波形,所有代码均经过本人验证。 目录如下: 1.数字IC手撕代码-分频器(任意偶数分频) 2.数字IC手撕代码-分频器(任意奇数分频) 3.数字IC手撕代码-分

    2024年02月02日
    浏览(39)
  • java实现websocket握手协议

    其中最重要的是最后几个换行不要丢,将字符串转成byte[]写给客户端即可 收到的掩码转换 下面是服务器向客户端发送消息

    2024年02月08日
    浏览(37)
  • 一致性协议浅析

    Paxos 发明者是大名鼎鼎的 Lesile Lamport。Lamport 虚拟了一个叫做 Paxos 的希腊城邦,城邦按照议会民主制的政治模式制定法律。在 Lesile Lamport 的论文中,提出了 Basic Paxos、Multi Paxos、Fast Paxos 三种模型。 Client :系统外部角色,请求发起者,类比于民众。 Proposer :接收 Client 请求,

    2024年01月18日
    浏览(45)
  • TCP | TCP协议格式 | 三次握手

    1.TCP协议 为什么需要 TCP 协议 ?TCP 工作在哪一层? IP网络层是不可靠的,TCP工作在传输层,保证数据传输的可靠性。 TCP全称为 “传输控制协议(Transmission Control Protocol”)。 TCP 是 面向连接的、可靠的、基于字节流 : 面向连接 :一定是「一对一」才能连接,不能像 UDP 协议

    2024年03月24日
    浏览(38)
  • 深入浅出AXI协议(3)——握手过程

            在之前的文章中我们快速地浏览了一下AXI4协议中的接口信号,对此我们建议先有一个简单的认知,接下来在使用到的时候我们还会对各种信号进行一个详细的讲解,在这篇文章中我们将讲述AXI协议的握手协议。         在前面的文章中我们已经简单说明了为什么需

    2024年02月10日
    浏览(44)
  • TCP协议3次握手4次挥手

    建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立,在socket编程中,这一过程由客户端执行connect来触发,在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。 TCP三次握手的过程如下: 第一次握手: Client将标志位SYN置为1,随机产生一

    2024年02月16日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包