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
|