数字IC备战校招day4(跨时钟域信号传输问题之握手同步)

跨时钟域信号传输问题之握手同步

所谓握手,即通信双方使用了专用控制信号进行状态指示,这个控制信号既有发送域给接受域的也有接收域给控制域的,有别于单向控制信号方式。
       使用握手协议方式处理跨时钟域数据传输时,只需要对双方的握手信号(req 和 ack)分别使用脉冲检测方法进行同步,在具体实现中,假设req ,ack, data,总线在初始化时都处于无效状态,发送域先把数据放入总线,随后发送有效的req信号给接收域;接收域在检测到有效的req信号后锁存数据总线,然后会送一个有效的ack信号表示读取完成应答;发送域在检测到有效ack信号后撤销当前的req信号,接收域在检测到req撤销后也相应撤销ack信号,此时完成一次正常握手通信,此后,发送域可以继续开始下一次握手通信,如此循环,该方式能够使接收到的数据稳定可靠,有效的避免了亚稳态的出现,但是控制信号握手检测会消耗通信双方较多的时间。
如下图为握手通信示意图:

发送域的Verilog设计:

module handshake_tclk(
	input tclk, //发送域的时钟和复位
	input resetb_tclk,
	input r_ack, //接收到的响应信号
	input data_avail, //从其他模块接收到的数据有效信号
	input [31:0] transmit_data, //需要发送出去的信号
	output t_rdy, //对于发送时钟域,需要输出数据准备好了的信号,以便在接收时钟域接收此信号,用来提示接收信号
	output [31:0] t_data //需要发送出去的信号
);
	localparam IDLE = 3'b001;     //空闲状态,判断数据是否有效,如果有效就输出t_rdy有效,表示数据准备好了
	localparam ASSERT_TRDY = 3'b010; //到了这个状态,表明t_rdy已经有效了,这时我们需要判断响应r_ack_tclk是否有效,如果有效则使t_rdy无效,否则保持不变
	localparam DEASSERT_TRDY = 3'b100; //到了这个t_rdy无效状态,需要考虑下一次的数据传输了,如果data_avail有效,则下一个状态进入ASSERT_TRDY,且t_rdy有效,否则进入空闲状态
	reg t_cur_state, t_nxt_state;
	reg t_rdy, t_rdy_nxt;
	reg [31:0] t_data, t_data_nxt;
	reg r_ack_d1, r_ack_tclk; //对于接收到的响应信号,需要进行时钟域同步,同步到发送时钟域
	always@(posedge tclk or negedge resetb_tclk) begin
		if(resetb_tclk) begin
				t_cur_state <= IDLE;
				t_rdy <= 0;
				//同步接收域的响应信号ack
				r_ack_d1 <= 0;
				r_ack_tclk <= 0;
		end
		else begin
				t_cur_state <= t_nxt_state;
				t_rdy <= t_rdy_nxt;
				r_ack_d1 <= r_ack;
				r_ack_tclk <= r_ack_d1;
		end
	end
	always@(*) begin
		t_nxt_state = t_cur_state;
		t_rdy_nxt = 0;
		t_data_nxt = t_data;
		case(t_cur_state) 
			IDLE: begin
				if(data_avail) begin
					t_nxt_state = ASSERT_TRDY;
					t_rdy_nxt = 1'b1;
					t_data_nxt = transmit_data;
				end
				else ; 
			end
			ASSERT_TRDY: begin
				if(r_ack_tclk) begin
					t_rdy_nxt = 1'b0;
					t_nxt_state = DEASSERT_TRDY;
					t_data_nxt = 'd0;
				end
				else begin
					t_rdy_nxt = 1'b1;
					t_data_nxt = t_data;
				end
			end
			DEASSERT_TRDY: begin
				if(!r_ack_tclk) begin
					if(data_avail) begin
						t_nxt_state = ASSERT_TRDY;
						t_rdy_nxt = 1'b1;
						t_data_nxt = transmit_data;
					end
					else t_nxt_state = IDLE;
				end
				else;
			end
			default: ;
 
		endcase
 
	end
 
 
 
endmodule

接收域设计代码:

 module handshake_rclk(
	input rclk,
	input resetb_rclk,
	input t_rdy,
	input [31:0] t_data,
	output r_ack
	);
 
	localparam IDLE = 2'b01;
	localparam ASSERT_ACK = 2'b10;
 
	reg r_cur_state, r_nxt_state;
	reg r_ack, r_ack_nxt;
	reg [31:0] t_data_rclk, t_data_rclk_nxt;
	reg t_rdy_d1, t_rdy_rclk;
 
	always@(posedge clk or negedge resetb_rclk) begin
		if(~resetb_rclk) begin
			r_cur_state <= IDLE;
			r_ack <= 0;
			t_data_rclk <= 0;
			t_rdy_d1 <= 0;
			t_rdy_rclk <= 0;
		end
		else begin
			r_cur_state <= r_nxt_state;
			r_ack <= r_ack_nxt;
			t_data_rclk <= t_data_rclk_nxt;
			t_rdy_d1 <= t_rdy;
			t_rdy_rclk <= t_rdy_d1;
		end
	end
 
	always@(*) begin
		r_nxt_state = r_cur_state;
		r_ack_nxt = 1'b0;
		t_data_rclk_nxt = t_data_rclk;
		case(r_nxt_state)
			IDLE: begin
				if(t_rdy_rclk) begin
					r_nxt_state = ASSERT_ACK;
					r_ack_nxt = 1'b1;
					t_data_rclk_nxt = t_data;
				end
				else;
			end
 
 
			ASSERT_ACK: begin
				if(~t_rdy_rclk) begin
					r_ack_nxt = 1'b0;
					r_nxt_state = IDLE;
				end
				else r_ack_nxt = 1'b1;
			end
 
		endcase
 
	end

综合上述两段设计程序,来大致总结下发送域的控制信号t_rdy和接收域的响应信号r_ack之间的关系;

最先是t_rdy有效,当接收域检测到t_rdy信号后,r_ack有效;

让发送域检测到r_ack后,t_rdy无效;

让接收域检测到t_rdy无效后,使r_ack无效,此时,一次完整的握手成功完成。
 

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2019/04/28 22:12:00
// Design Name: 
// Module Name: handshack_tb
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
 
 
module handshack_tb(
 
    );
	
	reg clk, rst_n;
	reg req;
	reg [7:0] datain;
	wire ack;
	wire [7:0] dataout;
	
	//--------------------------------------------------
	//产生时钟
	initial clk = 0;
	
	always begin
		#1 clk = ~clk; 
	end
	
	//------------------------------------------------------
	//初始化
	initial begin
		rst_n = 0;
		req = 0;
		
		#4
		rst_n = 1;
		#4
		datain = 8'h55;
		#2
		req = 1;
		#10
		req = 0;
		datain = 8'haa;
		#4
		req = 1;
		
		#10
		req = 0;
	
	end
	
	//------------------------------------------------------
	//调用模块
	handshack u_handshack(
	.clk(clk),
	.rst_n(rst_n),
	.req(req),
	.datain(datain),
	.ack(ack),
	.dataout(dataout)
	);
	
	
	
endmodule

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值