1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
|
//
// Copyright 2018 Ettus Research, A National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: pulse_synchronizer
// Description:
// - Synchronizes a single-cycle pulse or an edge from one
// clock domain to another
// - Clocks A and B can be asynchronous
//
module pulse_synchronizer #(
parameter MODE = "PULSE", // Capture mode {PULSE, POSEDGE, NEGEDGE}
parameter STAGES = 2 // Number of synchronizer stages
) (
input clk_a, // Clock A
input rst_a, // Reset in clock domain A
input pulse_a, // Pulse in clock domain A to synchronize
output busy_a, // Synchronizer is busy (pulse_a ignored when asserted)
input clk_b, // Clock B
output pulse_b // Pulse in clock domain B
);
// Trigger logic based on the capture mode
wire trigger;
generate if (MODE == "POSEDGE") begin
reg pulse_a_del_pe = 1'b0;
always @ (posedge clk_a)
pulse_a_del_pe <= rst_a ? 1'b0 : pulse_a;
assign trigger = pulse_a & ~pulse_a_del_pe;
end else if (MODE == "NEGEDGE") begin
reg pulse_a_del_ne = 1'b1;
always @ (posedge clk_a)
pulse_a_del_ne <= rst_a ? 1'b1 : pulse_a;
assign trigger = ~pulse_a & pulse_a_del_ne;
end else begin
assign trigger = pulse_a;
end endgenerate
// Translate pulse/edge to a level and synchronize that into the B domain
reg pulse_toggle_a = 1'b0;
always @(posedge clk_a) begin
pulse_toggle_a <= rst_a ? 1'b0 : (pulse_toggle_a ^ (trigger & ~busy_a));
end
wire pulse_toggle_b;
reg pulse_toggle_b_del = 1'b0;
wire handshake_toggle_a;
synchronizer #(
.STAGES(STAGES), .INITIAL_VAL(0)
) toggle_sync_i (
.clk(clk_b), .rst(1'b0), .in(pulse_toggle_a), .out(pulse_toggle_b)
);
// Handshake toggle signal back into the A domain to deassert busy
synchronizer #(
.STAGES(STAGES), .INITIAL_VAL(0)
) handshake_sync_i (
.clk(clk_a), .rst(1'b0), .in(pulse_toggle_b_del), .out(handshake_toggle_a)
);
always @(posedge clk_b) begin
pulse_toggle_b_del <= pulse_toggle_b;
end
assign pulse_b = pulse_toggle_b_del ^ pulse_toggle_b;
assign busy_a = pulse_toggle_a ^ handshake_toggle_a;
endmodule
|