跨时钟域刷题

单比特处理

跨时钟域的信号分为两类,一类是单比特的信号,一类是多比特的信号。
对于单比特信号,可以分为两种情况:

  1. 慢时钟到快时钟:一般通过加两级触发器的方式处理,即所说的打两拍,另外若多比特数据每次只有一个比特发生变化,也可以采用多级寄存器同步的方法,例如采用格雷码。
  2. 快时钟到慢时钟:快时钟域的信号脉宽较窄,慢时钟域不一定能采到,可以通过握手机制让窄脉冲展宽,慢时钟域采集到信号后再“告诉”快时钟域已经采集到信号,确保能采集到。

多比特信号处理

对于多比特信号:一般采用异步FIFO、异步双口RAM、握手、格雷码方式处理。
在这里插入图片描述
该题为笔试遇到的遇到真题,该题主要考察了多比特信号的处理,且为慢时钟域到快时钟域。
思路:将计数结果换成格雷码,并在快时钟域下打两拍处理。

1.代码实现:

/*
 * @Author: yaohao 
 * @Date: 2022-06-18 10:12:34 
 * @Last Modified by: yaohao
 * @Last Modified time: 2022-06-18 11:03:13
 */

module cross_clock_domain(
                           input clk0, 
                           input clk1, 
                           input rst1, 
                           input rst0, 
                           output reg [3:0]cnt_o 
                        );
    wire [3:0]sum;
    reg [3:0]cnt;

    assign sum = cnt + 1'd1;
    always @(posedge clk0 or negedge rst0) begin //产生一个4bit的计数器
        if(!rst0)
            begin
                cnt <= 4'd0;
            end
        else begin
                cnt <= sum;
            end
    end

    wire [3:0]cnt_g;    //定义格雷码形式的cnt
    assign cnt_g = cnt ^ (cnt>>1);

    reg [3:0] cnt_g1, cnt_g2;    //打拍处理cdc问题
    always @(posedge clk1 ) begin   //将计数结果从clk0同步到clk1
        if(!rst1) 
            begin
                cnt_g1 <= 4'd0;
                cnt_g2 <= 4'd0;
            end
        else begin
            cnt_g1 <= cnt_g;
            cnt_g2 <= cnt_g1;
            end
    end

    always @(posedge clk1 ) begin
        if(!rst1)
            begin
                cnt_o <= 4'd0;
            end
        else begin
            cnt_o <= cnt_g2;
            end
    end
endmodule

`timescale 1ns/1ns

module tb ();
        reg clk0, rst0;
        reg clk1, rst1;
        wire [3:0]cnt_o;

        cross_clock_domain dut(
                              .clk0(clk0),
                              .clk1(clk1),
                              .rst0(rst0),
                              .rst1(rst1),
                              .cnt_o(cnt_o)  
                            );
         //时钟
    initial begin
	    clk0 = 0;
		    forever begin
			#25 clk0 = ~clk0;	
		    end		
	end
	
    initial begin
        clk1 = 0;
        forever #15 clk1 = ~clk1;
    end

    initial begin
        rst0 = 0;
        rst1 = 0;
        #25; 
        rst0 = 1;
        rst1 = 1;
        #500;
        $finish();
        end

endmodule //cross_clock_domain

2.仿真结果如下:


当计数步进为2时,格雷码每次变化的数不为1,不满足单比特变化,在跨时钟域时容易出问题,使得采样有误。

步进为2时的仿真结果:

在这里插入图片描述

单比特信号处理(快到慢)

思路:将脉冲信号进行展宽,然后同步到慢时钟域,再将反馈回快时钟域的信号用来拉低展宽信号。

1.代码实现

/*
 * @Author: yaohao 
 * @Date: 2022-06-18 14:26:23 
 * @Last Modified by: yaohao
 * @Last Modified time: 2022-06-18 15:16:05
 */

module cdc(
	input wire clka,    //快时钟域
	input wire rst_n,
	input wire pulse_a,//a 时钟域的脉冲信号
	input wire clkb,
	output wire out_pulse,//b时钟域检测到的脉冲输出
	output wire singal_out//表示展宽以后的脉冲信号
	);
 
reg ext_pulse_a;    // 展宽信号a
reg ext_pulse_b;  
reg [1:0] ext_pulse_r;  //从b反馈回的信号
reg [1:0] pos_pulse_b;//检测同步过来的pulse_b的上升沿
 
assign singal_out = pos_pulse_b[1];
 
//在a时钟域下对脉冲信号进行展宽
always @(posedge clka or negedge rst_n)
	if(!rst_n)
		ext_pulse_a <= 1'b0;
	else if(pulse_a)
		ext_pulse_a <= 1'b1;
	else if(ext_pulse_r[1])//   反馈信号,表明已经成功展宽,则拉低展宽脉冲信号
		ext_pulse_a <= 1'b0;
	else 
		ext_pulse_a <= ext_pulse_a;
 
 
//将展宽信号同步到b时钟域
always @(posedge clkb or negedge rst_n) begin
	if (!rst_n) 
		ext_pulse_b <= 1'b0;
	else
		ext_pulse_b <= ext_pulse_a; 
end
 
//将ext_pulse_b同步回a
always @(posedge clka or negedge rst_n) begin
	if (!rst_n) 
		ext_pulse_r <= 2'b0;
	else
		ext_pulse_r <= {ext_pulse_r[0],ext_pulse_b};    //将ext_pulse_b信号传回a时钟域
end
 
 
 
//检测ext_pulse_b上升沿
always @(posedge clkb or negedge rst_n) begin
	if (!rst_n) 
		pos_pulse_b <= 2'b0;
	else
		pos_pulse_b <= {pos_pulse_b[0],ext_pulse_b}; 
		
end
 
assign  out_pulse = (pos_pulse_b[0] & ~pos_pulse_b[1]);
 
endmodule

`timescale 1ns/1ps
module tb_cdc();
 
reg clka;
reg clkb;
reg pulse_a;
wire out_pulse;
reg rst_n;
wire singal_out;
 
initial begin
	clka =0;
	clkb =0;
	rst_n =0;
	pulse_a =0;
	#100
	rst_n =1;
	# 100;
	pulse_a =1'b1;
	#10;
	pulse_a = 1'b0;	
	#100;
	pulse_a =1'b1;
	#10;
	pulse_a = 1'b0;	
 
end
 
always #5 clka =~clka;
always #10 clkb = ~clkb;
 
 
cdc cdc_inst(
	.clka(clka),
	.rst_n(rst_n),
	.pulse_a(pulse_a),//a 时钟域的脉冲信号
	.clkb(clkb),
	.out_pulse(out_pulse),//b时钟域检测到的脉冲输出
	.singal_out(singal_out)
	);
 
 
endmodule

2.仿真结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

借问众神明.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值