diff options
Diffstat (limited to 'fpga/usrp3/lib/control/pulse_synchronizer.v')
-rw-r--r-- | fpga/usrp3/lib/control/pulse_synchronizer.v | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/control/pulse_synchronizer.v b/fpga/usrp3/lib/control/pulse_synchronizer.v new file mode 100644 index 000000000..af3460878 --- /dev/null +++ b/fpga/usrp3/lib/control/pulse_synchronizer.v @@ -0,0 +1,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
\ No newline at end of file |