握手信号valid/ready的打拍技巧

一、前言
  • valid和ready信号,尤其是ready信号的时序一般很差,因为它通常是接收端通过组合逻辑输出的。当流水线的级数较多时,ready反压信号一级一级往前传递,时序将会变得更差。
  • 为了优化时序,通常需要对valid和ready信号进行打拍处理。但是由于握手信号的特点,使得这两个信号直接打拍时会发生协议错误,此时就需要使用一些技巧来解决这个问题。

通常对于握手信号的打拍处理有以下三种方式:

  • Forward Register Slice:仅处理valid和data信号的打拍
  • Backward Register Slice:仅处理ready信号的打拍
  • Full Register Slice:同时处理valid信号与ready信号的打拍
二、Forward Register Slice

传送门:valid-ready握手协议中valid及data信号的打拍技巧

module valid_flop
        (
        CLK,
        RESET,
        VALID_UP,
        READY_UP,
        DATA_UP,
        VALID_DOWN,
        READY_DOWN,
        DATA_DOWN
        );

//-----------------------------------------------------------------------------
parameter WIDTH            = 32                                                 ;

//-----------------------------------------------------------------------------
input                      CLK;
input                      RESET;
input                      VALID_UP;
output                     READY_UP;
input  [WIDTH-1:0]         DATA_UP;
output                     VALID_DOWN;
input                      READY_DOWN;
output [WIDTH-1:0]         DATA_DOWN                                            ;

//-----------------------------------------------------------------------------
wire                       CLK;
wire                       RESET;
wire                       VALID_UP;
wire                       READY_UP;
wire   [WIDTH-1:0]         DATA_UP;
//Down Stream
reg                        VALID_DOWN;
wire                       READY_DOWN;
reg    [WIDTH-1:0]         DATA_DOWN;

//-----------------------------------------------------------------------------
//Valid
always @(posedge CLK)
if (RESET)  VALID_DOWN <= 1'b0;
else        VALID_DOWN <= READY_UP ? VALID_UP : VALID_DOWN;
//Data
always @(posedge CLK)
if (RESET)  DATA_DOWN <= {WIDTH{1'b0}};
else        DATA_DOWN <= (READY_UP && VALID_UP) ? DATA_UP : DATA_DOWN;
//READY with buble collapsing.
assign READY_UP = READY_DOWN || ~VALID_DOWN;
//READY with no buble collapsing.
//assign READY_UP = READY_DOWN;
endmodule

在这里插入图片描述

中心思想:在接收端握手成功之前,发送端要将valid和data一直保持住!为了保证接收端在ready_i(READY_DOWN)信号有效时能够采集到data,data必须提前打拍。data在打拍时,使用的是接收端传递给发送端的ready_o(READY_UP)信号,而为了实现提前打拍,ready_o(READY_UP)的值可以等于ready_i(READY_DOWN)|| ~ (valid_o)VALID_DOWN

三、Backward Register Slice

芯片设计-skid buffer(ready打断) 这篇文章中详细介绍的方案一就是典型的skid buffer处理方式。

// ports
output reg     data_i_ready;
input          data_i_valid;
input [DW-1:0] data_i;

input           data_o_ready;
output          data_o_valid;
output [DW-1:0] data_o;

// signals
wire          buf_valid;
reg  [DW-1:0] buf_data;

// data_i_ready由组合逻辑改为时序逻辑
// assign data_i_ready = ~data_o_valid || data_o_ready;
always @ (posedge clk or negedge rst_n) begin
    if(!rst_n)
        data_i_ready <= 1; //有个buf放在那,因此复位后至少可以收一个数据。
    else if(data_o_ready)
        data_i_ready <= 1;
    else if(data_i_valid)  //在data_o_ready拉低后的那一个周期,如果没有数据过来,表明buf为空,可以进数据,data_i_ready保持为1
        data_i_ready <= 0; //如果有数据过来,buf被占,则不允许再进数据了,data_i_ready拉低。
end

// ************关于buf_valid和buf_data有2种方案
/*
方案1:所有输入端口的数据都会进入buf,但其实只有(!data_o_ready && data_i_valid && data_i_ready)时刻进去才会发挥作用
优点:控制逻辑简单;缺点:功耗有所增加
*/
always @ (posedge clk or negedge rst_n) begin
    if(!rst_n) //可能有些控制信号通过本模块的data端口进行传输,因此有必要进行复位。
        buf_data <= 0;
    else if(data_i_ready) //不挑时刻,所有数据都进,但是真正有效的还是(!data_o_ready && data_i_valid && data_i_ready)时刻的数据
        buf_data <= data_i;
end

assign buf_valid = ~data_i_ready;

/*
方案2:只有(!data_o_ready && data_i_valid && data_i_ready)时刻数据才会进入buf
优点:功耗略低;缺点:控制逻辑稍微复杂点
*/
always @ (posedge clk or negedge rst_n) begin
    if(!rst_n) 
        buf_data <= 0;
    else if(!data_o_ready && data_i_valid && data_i_ready) //该条件下,将向buf中存入数据
        buf_data <= data_i;
end

// 这段其实等效于assign buf_valid = ~data_i_ready; 写成下面这样更好理解
always @ (posedge clk or negedge rst_n) begin
    if(!rst_n) 
        buf_valid <= 0;
    else if(data_o_ready)
        buf_valid <= 0; //当data_o_ready拉高,优先读走buf中的数据。
    else if(!data_o_ready && data_i_valid && data_i_ready) //该条件下,将向buf中存入数据
        buf_valid <= 1; 
end

// out,如果buf中有数据,优先读走buf中的数据
assign data_o_valid = data_i_ready? data_i_valid : buf_valid;
assign data_o       = data_i_ready? data_i       : buf_data;

在这里插入图片描述
在这里插入图片描述

中心思想:在情况1时刻,如果输入端有数据进入,则使用buf对该数据进行暂存。在情况2时刻,如果buf中存有数据,则优先输出buf中的数据。

四、Full Register Slice

https://zhuanlan.zhihu.com/p/212356622 这篇文章中的FIFO处理模式就是Full Register Slice。

  • 4
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Valid-Ready握手协议在Verilog设计中用于数据传输的同步,确保数据的有效性和可靠性。它通常用于两个模块之间的数据交换,并且在发送数据之前,接收方必须准备好接收数据。 下面是一个简单的Verilog代码示例,演示了Valid-Ready握手协议的基本原理: ```verilog module ValidReadyHandshake ( input wire clk, input wire reset, input wire data_valid, output wire data_ready, input wire [DATA_WIDTH-1:0] data_in, output wire [DATA_WIDTH-1:0] data_out ); // 内部状态定义 reg [DATA_WIDTH-1:0] internal_data; reg internal_valid; reg internal_ready; // 同步时钟 always @(posedge clk) begin if (reset) begin internal_ready <= 1'b0; internal_data <= {DATA_WIDTH{1'b0}}; internal_valid <= 1'b0; end else begin internal_ready <= data_ready; internal_data <= data_in; internal_valid <= data_valid; end end // 数据输出逻辑 assign data_out = internal_data; // Ready信号逻辑 assign data_ready = internal_ready && !internal_valid; endmodule ``` 在这个示例中,Valid-Ready握手协议的发送方将数据放入`data_in`端口,并设置`data_valid`信号为高电平。接收方通过`data_ready`信号表示它已经准备好接收数据。当接收方准备好时,它将`data_ready`信号设置为高电平,发送方将通过`data_ready`信号的状态来判断是否可以发送数据。 值得注意的是,`clk`和`reset`信号是必需的,用于同步时钟和复位。 这只是一个基本示例,你可以根据具体的设计需求对握手协议进行扩展和修改。希望这个示例对你有所帮助!如果你有更多问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值