文章目录
- 为什么要握手
- 握手信号无非3种可能
- 怎样实现握手
- 案例一:数据反压
- 参考链接
为什么要握手
-
跨时钟域处理:
-
握手信号法其实也用到了脉冲展宽的方法,只是展宽信号的变化条件不同。因为如果不对脉冲进行展宽,慢速时钟域的时钟很有可能无法采集到快速时钟域的信号,所以要在脉冲展宽的基础上加反馈信号,即握手机制。
握手信号无非3种可能
- valid先变高:上游master提供的valid信号随数据一起拉高,但下游slave过一段时间才能准备好ready信号
- ready先变高:
- valid、ready一起变高:
怎样实现握手
案例一:数据反压
- 代码
`timescale 1ns/1nsmodule handshake(input clk,input rst_n,input valid_i,input [7:0] data_i,output ready_o,output [7:0] data_o,input ready_i,output valid_o
);reg [7:0] data_o_r;
reg valid_o_r;assign ready_o = ready_i;always@(posedge clk or negedge rst_n)beginif(!rst_n)begindata_o_r <= 8'b0;end else if(valid_i && ready_i)begindata_o_r <= data_i * 2;end
endalways@(posedge clk or negedge rst_n)beginif(!rst_n)beginvalid_o_r <= 1'b0;end else if(ready_i)beginvalid_o_r <= valid_i;end
endassign data_o = data_o_r;
assign valid_o = valid_o_r;endmodule
- testbench
`timescale 1ns/10psmodule handshake_tb();reg clk;
reg rst_n;reg valid_i;
reg [7:0] data_i;
wire ready_o;wire data_o;
reg ready_i;
wire valid_o;always #10 clk = ~clk;initial beginclk = 0;rst_n = 0;data_i = 8'd0;valid_i = 1'd0;ready_i = 1'd1;#15rst_n = 1'b1;#15rst_n <= 1'b1;data_i <= 8'b0000_1000;valid_i <= 1'd0; //upstream data invalidready_i <= 1'd1; //downstream ready#20data_i <= 8'b0111_1000;valid_i <= 1'd1; //upstream data valid#20data_i <= 8'b0100_0100; //upstream data change#20valid_i <= 1'd0; //upstream data invalid#20data_i <= 8'b0010_0100;valid_i <= 1'd1; //upstream data validready_i <= 1'd0; //downstream not ready#20ready_i <= 1'b1; //downstream ready#20valid_i <= 1'b0; //upstream data invalid#500$stop();
endhandshake u_handshake(.clk (clk ),.rst_n (rst_n ),.valid_i (valid_i),.data_i (data_i ),.ready_o (ready_o),.data_o (data_o ),.ready_i (ready_i),.valid_o (valid_o) );endmodule
结果
参考链接
- Verilog手撕代码(8)握手机制
- cdc跨时钟域处理-结绳握手法