b0VIM 8.12y_:Rlaforestscriptor~laforest/public_html/fpga/CDC_Pulse_Synchronizer_2phase.vutf-8 3210#"! UtpRoSad Ro FE+* [  h  q ]  F b  yxWVpA@T?Pr&YXBA output reg sending_ready, input wire sending_pulse_in, input wire sending_clock,() parameter CDC_EXTRA_DEPTH = 0#(module CDC_Pulse_Synchronizer_2phase`default_nettype none// a system at rest ready for the next 2-phase handshake.// sending level and the returned response are at the same value, denoting// a `ready` output on the sending side by noting when both the initial// a system will encounter. The toggle register enabling logic also acts as// delays for every possible sending to receiving clock frequency ratio// sending clock cycle. Fortunately, we don't have to compute inter-pulse// sending clock cycles between input pulses, or one input pulse every 4th// happen in the same cycle, there must be *at an absolute minimum* 3 idle// Since re-enabling the toggle register and receiving an input pulse can// pulse..// 4. The input toggle register is now re-enabled and can receive a new input// 3. CDC back into the sending clock domain: 3 cycles (worst case)// 2. CDC into the receving clock domain: 0 cycles// 1. Toggling the input register (and disabling it): 1 cycle// clock side:// meet setup timing), then we only need to sum up the latencies on the sending// response arrives soon enough within a single cycle of the sending clock to// "infinite" from the point of view of the sending clock (i.e.: the handshake// At the upper limit, when the receiving clock frequency is fast enough to be// register will have not been re-enabled yet.// If we exceed this rate, input pulses will be lost, as the input toggle// the input pulse rate, that also depends on the receiving clock frequency.// The time taken for the 2-phase handshake to complete puts an upper limit on//## Input Pulse Frequency Limit// sequence.// handshake. It does not depend on the timing of the signals, only their// response to also toggle into the same state, is a 2-phase asynchronous// input pulse. This process of toggling a signal, then waiting for the// system is back into one of its two rest states, ready to receive another// Once the initial signal and its response both reach the same value, the// * using that synchronized toggle signal to re-enable the toggle register// * synchronizing that toggle signal back into the sending clock domain,// edge) in the receiving clock domain,// * using that synchronized toggle signal to generate a pulse (on any toggle// * synchronizing the output of that toggle register into the receiving clock domain,// further toggles,// * first using the incoming pulse to toggle a register and disable// we solve this by:// as the receiving clock may not be able to sample the pulse correctly. So,// pass a pulse of unknown duration between clock domains of unknown relation,// We can't simply use a [CDC Synchronizer](./CDC_Bit_Synchronizer.html) to//## Theory of Operation// // the maximum rate of this 2-phase implementation. // latency across clock domains, so it can only accept input pulses at half// simpler hardware, but a more complex handshake leading to double the// Synchronizer](./CDC_Pulse_Synchronizer_4phase.html). It has slightly// For comparison, have a look at the [4-phase handshake Pulse//
// The output pulse is a single-cycle pulse in the receiving clock domain.// The recommended input is a single-cycle pulse in the sending clock domain.// the pulse duration. *Uses a 2-phase asynchronous handshake.*// another when we don't know anything about the relative clock frequencies or// Reliably passes a synchronous posedge pulse from one clock domain to//# Clock Domain Crossing (CDC) Pulse Synchronizer (2-phase handshake)adBoig t D  y r q # O p # s l O 0 *   rHCpjYS$p'& `2+*~`Z+_-&%endmodule ); .pulse_anyedge_out (receiving_pulse_out) // verilator lint_on PINCONNECTEMPTY .pulse_negedge_out (), .pulse_posedge_out (), // verilator lint_off PINCONNECTEMPTY .level_in (receiving_toggle), .clock (receiving_clock), ( receiving_toggle_to_pulse Pulse_Generator// We generate an output pulse on either of the toggle transitions.// Finally, convert the receiving toggle to a pulse in the receiving clock domain. ); .bit_out (toggle_response) .bit_in (receiving_toggle), .receiving_clock (sending_clock), ( to_sending ) .EXTRA_DEPTH (CDC_EXTRA_DEPTH) #( CDC_Bit_Synchronizer// signal that the CDC is complete and to re-enable the toggle register.// Now pass the synchronized toggle signal back to the sending clock domain to ); .bit_out (receiving_toggle) .bit_in (sending_toggle), .receiving_clock (receiving_clock), ( to_receiving ) .EXTRA_DEPTH (CDC_EXTRA_DEPTH) #( CDC_Bit_Synchronizer wire receiving_toggle;// Pass the toggle signal to the receiving clock domain end sending_ready = enable_toggle; enable_toggle = (sending_toggle == toggle_response); always @(*) begin// is complete and we are ready to toggle again.// When the toggle and its response have the same value, the 2-phase handshake ); .data_out (sending_toggle) .data_in (sending_toggle), .toggle (cleaned_pulse_in), .clear (1'b0), .clock_enable (enable_toggle), .clock (sending_clock), ( start_handshake ) .RESET_VALUE (1'b0) .WORD_WIDTH (1), #( Register_Toggle wire sending_toggle; reg enable_toggle = 1'b0; wire toggle_response;// will take effect, and so the spurious pulse could have side-effects.// clock domains would be cleared together, we can't be sure when each clear// if we could guarantee that the logic in both the sending and receiving// handshake and generate a spurious pulse in the receiving clock domain. Even// a high output, and we clear it, this will start a spurious 2-phase// NOTE: `clear` cannot be used here: if the toggle register happens to have// to keep the register output static when not toggling.// of a 2-phase asynchronous handshake. We feed the output back to the input// Now use that single-cycle pulse to toggle a register, signalling the start ); // verilator lint_on PINCONNECTEMPTY .pulse_anyedge_out () .pulse_negedge_out (), // verilator lint_off PINCONNECTEMPTY .pulse_posedge_out (cleaned_pulse_in), .level_in (sending_pulse_in), .clock (sending_clock), ( pulse_cleaner Pulse_Generator wire cleaned_pulse_in;// part of the design much harder to understand.// and NOT gates, but this saves no logic (only a register), and makes this// NOTE: It's possible to replace the Pulse_Generator with a a couple of AND// receiving clock domain.// is still high, causing a second toggle and thus a second pulse in the// a situation where the 2-phase handshake has completed and a long input pulse// Cleanup the input pulse to a single cycle pulse, so we cannot have); output wire receiving_pulse_out input wire receiving_clock,