-
Notifications
You must be signed in to change notification settings - Fork 43
/
Copy pathCDC_Pulse_Synchronizer_4phase.v
170 lines (135 loc) · 6.05 KB
/
CDC_Pulse_Synchronizer_4phase.v
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
//# Clock Domain Crossing (CDC) Pulse Synchronizer (4-phase handshake)
// Reliably passes a synchronous posedge pulse from one clock domain to
// another when we don't know anything about the relative clock frequencies or
// the pulse duration. *Uses a 4-phase asynchronous handshake.*
// The recommended input is a single-cycle pulse in the sending clock domain.
// The output is a single-cycle pulse in the receiving clock domain.
// <div class="bordered">
// Unless you *really* need to save a few gates, I would recommend you instead
// use the [2-phase handshake Pulse
// Synchronizer](./CDC_Pulse_Synchronizer_2phase.html), as it can accept input
// pulses at twice the maximum rate. This 4-phase implementation exists for
// comparison and education.
// </div>
//## Theory of Operation
// We can't simply use a [CDC Synchronizer](./CDC_Bit_Synchronizer.html) to
// pass a pulse of unknown duration between clock domains of unknown relation,
// as the receiving clock may not be able to sample the pulse correctly. So,
// we solve this by:
// * first latching the incoming pulse into a level signal,
// * synchronizing that level signal into the receiving clock domain,
// * using that synchronized level signal to generate a pulse,
// * synchronizing that same level back into the sending clock domain,
// * using that synchronized level to clear the original level signal.
// This process then happens all over again with the cleared level signal,
// which does not generate a pulse in the receiving clock domain, until the
// system is back into its original rest state, ready to receive another input
// pulse. This process of raising a signal, waiting for a response to rise,
// then dropping the first signal, then waiting for the response to drop, is
// a 4-phase asynchronous handshake. It does not depends on the timing of the
// signals, only their sequence.
//## Input Pulse Frequency Limit
// The time taken for the 4-phase handshake to complete puts an upper limit on
// the input pulse rate, that also depends on the receiving clock frequency.
// If we exceed this rate, input pulses will be lost, as the input pulse latch
// will have not been cleared yet.
// At the upper limit, when the receiving clock frequency is fast enough to be
// "infinite" from the point of view of the sending clock (i.e.: the handshake
// response arrives soon enough within a single cycle of the sending clock to
// meet setup timing), then we only need to sum up the latencies on the sending
// clock side:
// 1. Latching (or clearing) the input pulse: 1 cycle
// 2. CDC into the receving clock domain: 0 cycles
// 3. CDC back into the sending clock domain: 3 cycles (worst case)
// 4. The input latch now clears, and the steps 1, 2, and 3 repeat.
// Thus there must be *at an absolute minimum* 8 idle sending clock cycles
// between input pulses, or one input pulse every 9th sending clock cycle.
// (We can't overlap the clearing and latching, since clear has priority over
// input data in a [Register](./Register.html).) Fortunately, we don't have to
// compute inter-pulse delays for every possible sending to receiving clock
// frequency ratio a system will encounter. We can instead signal `ready` on
// the sending side by noting when both the initial sending level and the
// returned response are low, denoting a system at rest ready for the next
// 4-phase handshake.
`default_nettype none
module CDC_Pulse_Synchronizer_4phase
#(
parameter CDC_EXTRA_DEPTH = 0 // 0 or greater, if necessary
)
(
input wire sending_clock,
input wire sending_pulse_in,
output reg sending_ready,
input wire receiving_clock,
output wire receiving_pulse_out
);
initial begin
sending_ready = 1'b0;
end
// Capture the sending pulse into a level, and clear the latch once the level
// has passed into and returned from the receiving clock domain *and the
// sending pulse has ended*. This gating prevents a cycle of latch set/reset
// if the sending pulse is longer than the round-trip latency of level signal
// to and back from the receiving clock domain, causing a train of pulses in
// the receiving clock domain.
wire sending_level;
reg clear_sending = 1'b0;
wire level_response;
always @(*) begin
clear_sending = (level_response == 1'b1) && (sending_pulse_in == 1'b0);
end
Pulse_Latch
#(
.RESET_VALUE (1'b0)
)
sending_pulse_capture
(
.clock (sending_clock),
.clear (clear_sending),
.pulse_in (sending_pulse_in),
.level_out (sending_level)
);
// Pass the latched sending pulse to the receiving clock domain
wire receiving_level;
CDC_Bit_Synchronizer
#(
.EXTRA_DEPTH (CDC_EXTRA_DEPTH)
)
to_receiving
(
.receiving_clock (receiving_clock),
.bit_in (sending_level),
.bit_out (receiving_level)
);
// Now pass the synchronized level back to the sending clock domain to
// signal that the CDC is complete and to clear the latch.
CDC_Bit_Synchronizer
#(
.EXTRA_DEPTH (CDC_EXTRA_DEPTH)
)
to_sending
(
.receiving_clock (sending_clock),
.bit_in (receiving_level),
.bit_out (level_response)
);
// In parallel to all of the above, signal when both the sending level and the
// returned level from the receiving clock domain are low, indicating
// readiness for the next 4-phase handshake. *An input pulse sent while ready
// is low will be lost.*
always @(*) begin
sending_ready = (sending_level == 1'b0) && (level_response == 1'b0);
end
// Finally, convert the receiving level to a pulse in the receiving clock domain
Pulse_Generator
receiving_level_to_pulse
(
.clock (receiving_clock),
.level_in (receiving_level),
.pulse_posedge_out (receiving_pulse_out),
// verilator lint_off PINCONNECTEMPTY
.pulse_negedge_out (),
.pulse_anyedge_out ()
// verilator lint_on PINCONNECTEMPTY
);
endmodule