赞
踩
这里简单的说明一下,因为网上这方面资料比较多。简单来说,对于多bit信号,不能直接使用打两拍的方式来进行跨时钟域传输,因为各个信号的延时可能不同,打两拍可能会因为延时不同造成错误。
而使用MUX来进行跨时钟域传输,实际是通过一个使能信号去选通数据传输的通路,然后该选通信号是通过跨时钟域单bit信号处理方式进行处理的,首先对使能信号data enable和数据信号data bus在原时钟域打一拍,这是为了保持数据和使能信号的时序尽量一致。再在新时钟域对选通信号打两拍,这一方面是为了完成选通信号的同步,另一方面个人认为是完成使能信号的两拍延迟,从而保证使能信号完成同步后,数据信号已处于稳定,因而能保证数据传输的正确。
个人认为,MUX同步方式更适用于慢时钟域到快时钟域的传输,且数据信号最好持续几个时钟。因为使能信号需在新时钟域打两拍,如果新的时钟域更慢的话,这个两拍的时间对数据的影响可能太大了,甚至使能信号同步完成时数据已经结束了。
时钟:1MHz和10MHz(系统时钟sys_clk为50MHz)。为了更好的仿真,将clk_cnt_1初始值设定为20,来实现时钟相位的不同。
module clk_gen( input sys_clk, input sys_rst_n, output reg clk_1, //1MHz output reg clk_2 //10MHz ); reg [5:0] clk_cnt_1; reg [5:0] clk_cnt_2; always @(posedge sys_clk or negedge sys_rst_n) begin if(sys_rst_n==1'b0)begin clk_cnt_1<=5'd20; clk_cnt_2<=5'd0; clk_1<=1'b1; clk_2<=1'b0; end else begin clk_cnt_1<=(clk_cnt_1==6'd50)?6'd0:clk_cnt_1+1'b1; clk_cnt_2<=(clk_cnt_2==6'd5)?6'd0:clk_cnt_2+1'b1; clk_1<=(clk_cnt_1==6'd50)?~clk_1:clk_1; clk_2<=(clk_cnt_2==6'd5)?~clk_2:clk_2; end end endmodule
数据和使能信号的产生,数据每次加111(随便定的数字),使能信号在数据的第一个时钟产生:
module data_gen( input clk_1, input rst_n, output reg [15:0] data, output valid ); reg [3:0] cnt; assign valid=(cnt==4'd0)?1'b1:1'b0; always@(posedge clk_1 or negedge rst_n)begin if(!rst_n)begin data<=16'd0; cnt<=4'd0; end else begin cnt<=(cnt==4'd10)?4'd0:cnt+1'b1; data<=(cnt==4'd10)?data+16'd111:data; end end endmodule
跨时钟域实现代码:
module cdc( input clk_2, input clk_1, input [15:0] data, input valid, input rst_n, output reg [15:0] data_out ); reg valid_reg0,valid_reg1,valid_reg; reg [15:0] data_reg; always@(posedge clk_1 or negedge rst_n)begin if(!rst_n)begin data_reg<=16'd0; valid_reg<=1'b0; end else begin data_reg<=data; valid_reg<=valid; end end always@(posedge clk_2 or negedge rst_n)begin if(!rst_n) {valid_reg1,valid_reg0}<=2'd0; else {valid_reg1,valid_reg0}<={valid_reg0,valid_reg}; end always@(posedge clk_2 or negedge rst_n)begin if(!rst_n) data_out<=16'd0; else data_out<=valid_reg1?data_reg:data_out; end endmodule
顶层例化:
module top( input sys_clk, input rst_n ); wire clk_1,clk_2; wire [15:0] data; wire valid; wire [15:0] cdc_data; cdc u1( .clk_2(clk_2), .clk_1(clk_1), .data(data), .valid(valid), .rst_n(rst_n), .data_out(cdc_data) ); data_gen u2( .clk_1(clk_1), .rst_n(rst_n), .data(data), .valid(valid) ); clk_gen u3( .sys_clk(sys_clk), .sys_rst_n(rst_n), .clk_1(clk_1), .clk_2(clk_2) ); endmodule
testbench: module tb( ); reg rst_n; reg sys_clk; initial begin rst_n=1'b0; sys_clk=1'b0; #100 rst_n=1'b1; end always #10 sys_clk=~sys_clk; top u( .sys_clk(sys_clk), .rst_n(rst_n) ); endmodule
仿真结果,数据被同步到clk_2时钟域:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。