Verilog设计思路04——verilog快到慢跨时钟域传输和常见同步机制

一、slow_to_fast_sync模块用于将一个慢时钟信号同步到一个快时钟信号。以下是一个简单的例子,展示了如何实现这种同步。

module fast_to_slow_sync (
input wire fast_clk,
input wire reset,
output reg slow_clk );

// 计数器,用于分频
reg [27:0] counter;

always @(posedge fast_clk or posedge reset) begin
    if (reset) begin
        counter <= 28'd0;
        slow_clk <= 1'b0;
    end else begin
        if (counter == 28'd49_999_999) begin
            counter <= 28'd0;
            slow_clk <= ~slow_clk; // 反转慢时钟
        end else begin
            counter <= counter + 28'd1;
        end
    end
end

endmodule

二、slow_to_fast_sync模块用于将一个慢时钟信号同步到一个快时钟信号。以下是一个简单的例子,展示了如何实现这种同步。

module slow_to_fast_sync (
input wire slow_clk,
input wire reset,
output reg fast_clk );

// 计数器,用于分频
reg [27:0] counter;

always @(posedge slow_clk or posedge reset) begin
    if (reset) begin
        counter <= 28'd0;
        fast_clk <= 1'b0;
    end else begin
        if (counter == 28'd24_999_999) begin
            counter <= 28'd0;
            fast_clk <= ~fast_clk; // 反转快时钟
        end else begin
            counter <= counter + 28'd1;
        end
    end
end

endmodule

三、同步机制通常用于处理时钟信号,以确保数据在时钟边沿正确传输。以下是一些常见的同步机制及其代码示例:

  1. 双沿触发器同步(Double-Edge Triggered Flip-Flop Synchronizer)
    双沿触发器同步器使用两个触发器来同步信号。第一个触发器在时钟的上升沿触发,第二个触发器在时钟的下降沿触发。

module double_edge_trigger_sync (
input wire clk,
input wire reset,
input wire data_in,
output reg data_out );

reg data_mid;

always @(posedge clk or posedge reset) begin
    if (reset) begin
        data_mid <= 1'b0;
        data_out <= 1'b0;
    end else begin
        data_mid <= data_in;
        data_out <= data_mid;
    end
end

endmodule

  1. 异步复位同步器(Asynchronous Reset Synchronizer)
    异步复位同步器使用一个触发器来同步信号,并在复位信号为高时将输出重置。

module async_reset_sync (
input wire clk,
input wire reset,
input wire data_in,
output reg data_out );

always @(posedge clk or posedge reset) begin
    if (reset) begin
        data_out <= 1'b0;
    end else begin
        data_out <= data_in;
    end
end

endmodule

  1. 同步复位同步器(Synchronous Reset Synchronizer)
    同步复位同步器使用一个触发器来同步信号,并在复位信号为高时将输出重置。

module sync_reset_sync (
input wire clk,
input wire reset,
input wire data_in,
output reg data_out );

reg data_mid;

always @(posedge clk) begin
    if (reset) begin
        data_mid <= 1'b0;
        data_out <= 1'b0;
    end else begin
        data_mid <= data_in;
        data_out <= data_mid;
    end
end

endmodule

  1. 双沿触发器同步器(Double-Edge Triggered Flip-Flop Synchronizer with Reset)
    双沿触发器同步器使用两个触发器来同步信号,并在复位信号为高时将输出重置。

module double_edge_trigger_reset_sync (
input wire clk,
input wire reset,
input wire data_in,
output reg data_out );

reg data_mid;

always @(posedge clk or posedge reset) begin
    if (reset) begin
        data_mid <= 1'b0;
        data_out <= 1'b0;
    end else begin
        data_mid <= data_in;
        data_out <= data_mid;
    end
end

endmodule

在 Verilog 中,同步机制主要用于处理不同时钟域之间的数据传输和交互,以避免亚稳态问题,确保电路的稳定性和正确性。以下是常见的同步机制及其原理和示例代码。
5. 双触发器同步器(Two - Flip - Flop Synchronizer)
原理
双触发器同步器是最基本的跨时钟域同步方法,用于将一个时钟域的信号同步到另一个时钟域。它通过两级触发器对输入信号进行采样,利用第二级触发器的输出作为同步后的信号,从而减少亚稳态传播到后续电路的概率。
适用场景
适用于慢时钟域到快时钟域的单比特信号同步,例如异步复位信号的同步。
示例代码

module two_flip_flop_synchronizer (
input wire clk, // 目标时钟
input wire async_in, // 异步输入信号
output reg sync_out // 同步输出信号 );

reg sync1;

always @(posedge clk) begin
    sync1 <= async_in;
    sync_out <= sync1;
end

endmodule

  1. 脉冲同步器(Pulse Synchronizer)
    原理
    脉冲同步器用于将一个时钟域的脉冲信号同步到另一个时钟域。它通过检测脉冲信号的上升沿或下降沿,生成一个脉冲,并将其同步到目标时钟域。
    适用场景
    适用于快时钟域到慢时钟域的脉冲信号同步。
    示例代码

module pulse_synchronizer (
input wire fast_clk, // 快时钟
input wire fast_pulse, // 快时钟域的脉冲信号
input wire slow_clk, // 慢时钟
output reg slow_pulse // 慢时钟域的同步脉冲信号 );

reg fast_pulse_ff1, fast_pulse_ff2;
reg slow_pulse_ff1, slow_pulse_ff2;

// 在快时钟域对脉冲信号进行处理
always @(posedge fast_clk) begin
    fast_pulse_ff1 <= fast_pulse;
    fast_pulse_ff2 <= fast_pulse_ff1;
end

// 双触发器同步到慢时钟域
always @(posedge slow_clk) begin
    slow_pulse_ff1 <= fast_pulse_ff2;
    slow_pulse_ff2 <= slow_pulse_ff1;
end

// 生成慢时钟域的脉冲
always @(posedge slow_clk) begin
    slow_pulse <= slow_pulse_ff1 & ~slow_pulse_ff2;
end

endmodule

  1. 异步 FIFO(Asynchronous FIFO)
    原理
    异步 FIFO 用于在两个不同时钟域之间进行数据缓冲和同步。它包含写端口和读端口,分别由不同的时钟驱动。写操作将数据写入 FIFO 的存储单元,读操作从 FIFO 中读取数据。通过使用格雷码计数器来指示读写指针的位置,避免了指针在不同时钟域之间的亚稳态问题。
    适用场景
    适用于大量数据在不同时钟域之间的传输,例如高速数据采集系统中,将采集时钟域的数据传输到处理时钟域。
    示例代码

module async_fifo #(
parameter DATA_WIDTH = 8,
parameter ADDR_WIDTH = 4 ) (
input wire wr_clk, // 写时钟
input wire rd_clk, // 读时钟
input wire rst_n, // 异步复位,低电平有效
input wire wr_en, // 写使能
input wire rd_en, // 读使能
input wire [DATA_WIDTH-1:0] wr_data, // 写入数据
output reg [DATA_WIDTH-1:0] rd_data, // 读出数据
output reg full, // FIFO 满标志
output reg empty // FIFO 空标志 );

localparam DEPTH = 1 << ADDR_WIDTH;

reg [DATA_WIDTH-1:0] mem [DEPTH-1:0];
reg [ADDR_WIDTH:0] wr_ptr;
reg [ADDR_WIDTH:0] rd_ptr;
reg [ADDR_WIDTH:0] wr_ptr_gray;
reg [ADDR_WIDTH:0] rd_ptr_gray;
reg [ADDR_WIDTH:0] wr_ptr_gray_sync;
reg [ADDR_WIDTH:0] rd_ptr_gray_sync;

// 写指针和格雷码转换
always @(posedge wr_clk or negedge rst_n) begin
    if (!rst_n) begin
        wr_ptr <= 0;
        wr_ptr_gray <= 0;
    end else if (wr_en && !full) begin
        wr_ptr <= wr_ptr + 1;
        wr_ptr_gray <= (wr_ptr >> 1) ^ wr_ptr;
    end
end

// 读指针和格雷码转换
always @(posedge rd_clk or negedge rst_n) begin
    if (!rst_n) begin
        rd_ptr <= 0;
        rd_ptr_gray <= 0;
    end else if (rd_en && !empty) begin
        rd_ptr <= rd_ptr + 1;
        rd_ptr_gray <= (rd_ptr >> 1) ^ rd_ptr;
    end
end

// 双触发器同步写指针到读时钟域
always @(posedge rd_clk or negedge rst_n) begin
    if (!rst_n) begin
        wr_ptr_gray_sync <= 0;
    end else begin
        wr_ptr_gray_sync <= wr_ptr_gray;
    end
end

// 双触发器同步读指针到写时钟域
always @(posedge wr_clk or negedge rst_n) begin
    if (!rst_n) begin
        rd_ptr_gray_sync <= 0;
    end else begin
        rd_ptr_gray_sync <= rd_ptr_gray;
    end
end

// 计算满标志
always @(*) begin
    full = (wr_ptr_gray == {~rd_ptr_gray_sync[ADDR_WIDTH:ADDR_WIDTH-1],

rd_ptr_gray_sync[ADDR_WIDTH-2:0]});
end

// 计算空标志
always @(*) begin
    empty = (rd_ptr_gray == wr_ptr_gray_sync);
end

// 写操作
always @(posedge wr_clk) begin
    if (wr_en && !full) begin
        mem[wr_ptr[ADDR_WIDTH-1:0]] <= wr_data;
    end
end

// 读操作
always @(posedge rd_clk) begin
    if (rd_en && !empty) begin
        rd_data <= mem[rd_ptr[ADDR_WIDTH-1:0]];
    end
end

endmodule

  1. 握手协议(Handshaking Protocol)
    原理
    握手协议通过在发送方和接收方之间传递控制信号,确保数据在不同时钟域之间的可靠传输。发送方在数据准备好后发送请求信号,接收方在准备好接收数据时发送应答信号,双方通过这种方式进行同步。
    适用场景
    适用于对数据传输可靠性要求较高的场景,例如不同模块之间的通信。
    示例代码

module handshaking_protocol (
input wire clk_tx, // 发送方时钟
input wire clk_rx, // 接收方时钟
input wire rst_n, // 异步复位,低电平有效
input wire [7:0] data_in, // 输入数据
output reg [7:0] data_out // 输出数据 );

reg req_tx, ack_tx;
reg req_rx, ack_rx;
reg [7:0] data_reg;

// 发送方逻辑
always @(posedge clk_tx or negedge rst_n) begin
    if (!rst_n) begin
        req_tx <= 0;
        ack_tx <= 0;
    end else if (!req_tx) begin
        req_tx <= 1;
        data_reg <= data_in;
    end else if (ack_tx) begin
        req_tx <= 0;
    end
end

// 接收方逻辑
always @(posedge clk_rx or negedge rst_n) begin
    if (!rst_n) begin
        req_rx <= 0;
        ack_rx <= 0;
    end else if (req_rx) begin
        data_out <= data_reg;
        ack_rx <= 1;
    end else if (ack_rx) begin
        ack_rx <= 0;
    end
end

// 同步请求信号到接收方时钟域
always @(posedge clk_rx or negedge rst_n) begin
    if (!rst_n) begin
        req_rx <= 0;
    end else begin
        req_rx <= req_tx;
    end
end

// 同步应答信号到发送方时钟域
always @(posedge clk_tx or negedge rst_n) begin
    if (!rst_n) begin
        ack_tx <= 0;
    end else begin
        ack_tx <= ack_rx;
    end
end

endmodule

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

逻辑森林

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

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

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

打赏作者

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

抵扣说明:

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

余额充值