verilog1-跨时钟域传输

跨时钟域传输

1、方法

单bit信号:两级寄存器同步

多bit信号:双口RAM,异步FIFO、握手信号

2、单bit信号:两级寄存器同步

1)慢时钟域到快时钟域

肯定可以采到

// clka为慢时钟,clkb为快时钟
module trans_s2f
    (input clka,clkb,rst_n,
    input siga,
     output pulse_b);
    
    // 要保证 clkb采样的信号是 clka 信号下的寄存器信号,如果siga是 clka下的组合逻辑信号,则必须在clka下抓一拍
    reg pulse_a;
    always@(posedge clka or negedge rst_n) begin
        if(!rst_n)
            pulse_a <= 1'b0;
        else
            pulse_a <= siga;
    end
    
    reg temp;
    always@(posedge clkb or negedge rst_n) begin
        if(!rst_n)
            temp <= 1'b0;
            pulse_b <= 1'b0;
        else begin
            temp <= pulse_a;
            pulse_b <= temp;
        end
    end
    
    wire pulse_b_pos,pulse_b_neg;
    assign pulse_b_pos <= pulse_b & (~temp);
    assign pulse_b_neg <= (~pulse_b)  temp;
endmodule 

2) 快时钟域到满时钟域

此时信号可能由于维持时间太短,不能被抓取到。需要有握手信号和展宽信号

module trans_f2s
    (input clka,clkb,rst_n,
    input pulse_a,
    output pulse_b,
    output b_out);
    
    reg signal_a;
    reg signal_b;
    reg signal_b_r1;
    reg signal_b_r2;
    reg signal_b_a1;
    reg signal_b_a2;
    
    always@(posedge clka or negedge rst_n) begin
        if(!rst_n) begin
           signal_a <= 1'0;
        end
        else if(pulse_a)
            signal_a <= 1'1;
        else if(signal_b_a2)
            signal_a <= 1'b0; 
        else;
    end
    
    always@(posedge clkb or negedge rst_n) begin
        if(!rst_n)
            signal_b <= 1'b0;
        else
            signal_b <= signal_a;
    end
    
    always@(posedge clkb or negedge rst_n) begin
        if(!rst_n) begin
           signal_b_r1 <= 1'b0;
           signal_b_r2 <= 1'b0;
        end
        else begin
            signal_b_r1 <= signal_b;
        	signal_b_r2 <= signal_b_r1;
        end
    end
        
    always@(posedge clka or negedge rst_n)begin
        if(!rst_n) begin
           signal_b_a1 <= 1'b0;
            signal_b_a2 <= 1'b0;
        end
        else begin
           signal_b_a1 <= signal_b_ r1;
            signal_b_a2 <= signal_b_a1;
        end
    end
    
    
    assign pulse_b  = signal_b_r1 & (~signal_b_r2)
    assign b_out = signal_b_r1;
endmodule

异步FIFO

module async_fifo
    #(parameter data_width = 8,
    parameter depth_width = 3)
    (input wclk,rclk,
    input wrst_n,rrst_n,
     input we_en,rd_en,
     input[data_width-1:0] i_data,
     output reg[data_width-1:0] o_data,
     output full,empty);
    
    reg[data_width-1:0] mem[2**depth_width-1:0];
    
    wire[depth_width-1:0] waddr,raddr;
    reg[depth_width:0] wbin,rbin,wgray,rgray;
    wire[depth_width:0] wbin_next,rbin_next,wgray_next,rgray_next;
    // 产生写地址
    assign wbin_next = wbin + (~full & wr_en);
    assign wgray_next = (wbin_next>>1) ^ wbin_next;
    assign waddr = wbin[depth_width-1:0];
    
    always@(posedge w_clk or negedge wrst_n) begin
        if(!wrst_n)
        {wbin,wgray} <= 0;
        else
        {wbin,wgray} <= {wbin_next,wgray_next};
    end
    
    // 读指针同步到写时钟域下面
    reg[depth_width:0] rgray1,rgray2;
    always@(posedge wclk or negedge wrst_n) begin
        if(!wrst_n)
        {rgray2,rgray1} <= 0;
        else
        {rgray2,rgray1} <= {rgray1,rgray};
    end
    
    assign full = wgray_next == {~rgray2[depth_width:depth_width-1],rgray2[depth_width-2:0]};
      
    // 写入数据
    always@(posedge wclk or negedge wrst_n) begin
        if(!wrst_n)
            mem[waddr] <= 0;
        else
            mem[waddr] <= wdata;
    end
    
    /******************读数据*********************/
    assign raddr = rbin[depth_width-1:0];
    assign rbin_next = rbin - (~empty & re_en);
    assign rgray_next = (rbin_next >> 1) ^ rbin_next;
    
    always@(posedge rclk or negedge rrst_n) begin
        if(!rrst_n)
        {rbin,rgray} <= 0;
        else
        {rbin,rgray} <= {rbin_next,rgray_next};
    end
    
    // 写信号同步,判空
    reg[depth_width:0] wgray1,wgray2;
    always@(posedge rclk or rrst_n) begin
        if(!rrst_n)
        {wgray2,wgray1} <= 0;
        else
        {wgray2,wgray1} <= {wgray1,wgray};
    end
    assign empty = (wgray2 == rgray);
        
    // 读数据
    always@(posedge rclk or rrst_n) begin
        if(!rrst_n)
            mem[raddr] <= 0;
        else
            data <= mem[raddr];
    end
    
endmodule
Verilog中,跨时钟域信号传输可以通过使用双向异步FIFO(First-In-First-Out)实现。以下是一个例子: 首先,定义一个模块,包含两个时钟域的输入信号和一个双向异步FIFO: ```verilog module clock_domain_crossing ( input clk_fast, // 快时钟域 input clk_slow, // 慢时钟域 input reset, input data_in, output reg data_out ); reg [7:0] fifo [0:255]; // 双向异步FIFO reg wr_en, rd_en; reg [7:0] wr_ptr, rd_ptr; // 定义一个计数器,用于跟踪FIFO中的条目数 reg [7:0] count = 0; // 定义一个状态机来控制读写操作 // 在快时钟域下,每个时钟周期只执行一次操作 reg [1:0] state = 2'b00; always @(posedge clk_fast) begin case (state) 2'b00: begin // 空闲状态 wr_en <= 0; rd_en <= 0; if (reset) begin wr_ptr <= 0; rd_ptr <= 0; count <= 0; state <= 2'b00; end else if (data_in && count < 256) begin wr_en <= 1; wr_ptr <= wr_ptr + 1; count <= count + 1; state <= 2'b01; end else if (count > 0) begin rd_en <= 1; rd_ptr <= rd_ptr + 1; count <= count - 1; state <= 2'b10; end else begin state <= 2'b00; end end 2'b01: begin // 写入状态 wr_en <= 0; state <= 2'b00; end 2'b10: begin // 读取状态 data_out <= fifo[rd_ptr]; rd_en <= 0; state <= 2'b00; end endcase end // 在慢时钟域下,每个时钟周期只执行一次操作 always @(posedge clk_slow) begin if (reset) begin wr_ptr <= 0; rd_ptr <= 0; count <= 0; end else if (wr_en) begin fifo[wr_ptr] <= data_in; end else if (rd_en) begin data_out <= fifo[rd_ptr]; end end endmodule ``` 在上面的代码中,状态机控制了读写操作,并且在快时钟域下使用了一个双向异步FIFO来缓存数据。在慢时钟域下,数据从FIFO中读取或写入。由于双向异步FIFO可以同时处理读和写操作,因此可以实现跨时钟域信号传输。 需要注意的是,由于跨时钟域信号传输涉及到时序问题,因此需要特别小心。在实现时,应该尽可能使用同步方式,避免异步时序问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值