在跨时钟域(一)中,我们介绍了打两拍的方法,尽管这个方法可以有效处理单bit跨时钟域信号的亚稳态问题,但是当发送方的时钟比接收方的时钟快时,有可能出现信号有效时间过段,接收方采样不到的情况。握手就是解决这一问题的有效方法,同时,握手还可以解决多bit跨时钟域信号的同步。本文就对该方法作一介绍。
同步握手
同一时钟控制下的握手过程比较简单,这里以著名的AXI4协议为例,如下图所示
发送方要发送数据的时候,就拉高VALID信号,同时把要发送的数据放到数据总线上,接受方看到VALID信号为高,并且自己也有时间接受数据,于是拉高READY信号,表示数据已经被接收,发送方看到接受方已完成数据的接收,于是拉低VALID信号,同时接收方也拉低READY信号,一次握手完成。可以看到,在上图的情况中,数据的读取发生在VALID和READY信号同为高的时候,这就是一个典型的握手过程。
异步握手
在跨时钟域的情况下,握手的过程略有不同,首先,为了防止亚稳态的出现,我们必须将VALID信号同步到接收方的时钟域中,同时,接收方拉高的READY信号也必须同步到发送方的时钟域中,才能被使用。与此同时,接收方在拉高READY信号之后,还需经过几个周期才会同步到发送方的时钟域,因此VALID信号不会马上拉低,进而接收方同步过来的VALID信号也不会马上拉低,这会导致接收方以为是下一个VALID信号的到来。因此,为了解决这个问题,我们不检测VALID的高电平信息,转而检测VALID的上升沿信息,同理READY信号同步的时候也这么做。
RTL代码如下:
sender.sv
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/02/22 20:50:31
// Design Name:
// Module Name: sender
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module sender(
input logic sclk,
input logic rst,
input logic start,
input logic [31:0] data,
output logic valid,
output logic [31:0]sdata,
input logic ready //从另一个时钟域来的ready信号
);
logic ready_ff1;
logic ready_ff2;
logic ready_ff3;
logic pulse;
assign pulse=ready_ff2&&~ready_ff3; //检测read_ff3上升沿
always_ff@(posedge sclk,posedge rst)
if(rst)
begin
ready_ff1<=0;
ready_ff2<=0;
ready_ff3<=0;
end
else
begin
ready_ff1<=ready;
ready_ff2<=ready_ff1;
ready_ff3<=ready_ff2;
end
//valid
always_ff@(posedge sclk,posedge rst)
if(rst)
valid<=0;
else if(start)
valid<=1;
else if(pulse)
valid<=0;
//sdata
always_ff@(posedge sclk,posedge rst)
if(rst)
sdata<=0;
else if(start)
sdata<=data;
endmodule
上述代码中的pulse信号就是对VALID上升沿的检测。
receiver.sv
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/02/22 21:15:54
// Design Name:
// Module Name: receiver
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module receiver(
input logic rclk,
input logic rst,
input logic [31:0]sdata, //来自另一个时钟域的sdata
input logic valid, //来自另一个时钟域的valid
output logic ready,
output logic [31:0] dout
);
logic valid_ff1;
logic valid_ff2;
logic valid_ff3;
logic pulse;
//valid信号同步至rclk时钟域
always_ff@(posedge rclk)
begin
valid_ff1<=valid;
valid_ff2<=valid_ff1;
valid_ff3<=valid_ff2;
end
//pluse
always_comb
begin
pulse=valid_ff2&&~valid_ff3; //检测valid_ff3的上升沿
end
//dout
always_ff@(posedge rclk,posedge rst)
if(rst)
dout<=0;
else if(pulse)
dout<=sdata;
//ready
always_ff@(posedge rclk,posedge rst)
if(rst)
ready<=0;
else if(pulse)
ready<=1;
else
ready<=0;
endmodule
top模块
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/02/22 20:49:47
// Design Name:
// Module Name: handshake
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module handshake(
input logic rclk,
input logic sclk,
input logic rst,
input logic start,
input logic [31:0] data
);
logic ready;
logic valid;
logic [31:0] sdata;
logic [31:0] dout;
sender U1(.*);
// input logic sclk,
// input logic rst,
// input logic start,
// input logic [31:0] data,
// output logic valid,
// output logic [31:0]sdata,
// input logic ready //从另一个时钟域来的ready信号
// );
receiver U2(.*);
// input logic rclk,
// input logic rst,
// input logic [31:0]sdata, //来自另一个时钟域的sdata
// input logic valid, //来自另一个时钟域的valid
// output logic ready,
// output logic [31:0] dout
endmodule
测试平台文章来源:https://www.toymoban.com/news/detail-663742.html
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/02/22 21:41:49
// Design Name:
// Module Name: test_tb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module test_tb;
parameter PERIOD_S = 10;
parameter PERIOD_R = 17;
logic rclk;
logic sclk;
logic rst;
logic start;
logic [31:0] data;
//rclk
initial begin
rclk=0;
forever begin
#(PERIOD_R/2) rclk=~rclk;
end
end
//sclk
initial
begin
sclk=0;
forever
begin
#(PERIOD_S/2) sclk=~sclk;
end
end
//rst
initial
begin
rst=1;
#50
rst=0;
end
//start
initial
begin
start=0;
#(100+$random%100)
start=1;
#(PERIOD_S)
start=0;
end
//data
initial
begin
data=23;
end
handshake U(.*);
// input logic rclk,
// input logic sclk,
// input logic rst,
// input logic start,
// input logic [31:0] data
// );
endmodule
仿真波形
文章来源地址https://www.toymoban.com/news/detail-663742.html
到了这里,关于跨时钟域处理(三)---握手的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!