Cross Two Clock Domains
1. Slower to Faster Clock Domain
It’s pretty straightforward to send signal from a slower clock domain to a faster clock domain. The basic assumption is that the faster clock can always capture the signal changes, i.e. the edge from low to high or high to low in the slower clock domain, provided that the metastability is taken care of. By shifting that signal into a three-bit shift register, the faster clock can capture that rising/falling edge signal to produce a single clock cycle flag signal.
reg [2:0] edge_detect;
always @(posedge fast_clk) begin
edge_detect <= {edge_detect[1:0], slow_signal};
end
wire fast_clk_flag = edge_detect[1] ^ edge_detect[2];
The XOR operator would capture both the rising and falling edges of the slow_signal
. On the other hand, if you only need to capture the rising edge:
wire fast_clk_flag = edge_detect[2:1] == 2'b01;
Now comes the question: how do we pass a one clock cycle flag signal from a faster clock domain into the slower clock domain.
2. Faster to Slower Clock Domain
For a flag signal that lasts only one faster clock cycle, the slower clock won’t be able to capture it. The trick is to turn that flag into a single-shot long lasting pulse, so that the slower clock can sample it into a shift register, and the rest is the same as before.
To make that single-shot long pulse, XOR comes to help again.
always @(posedge fast_clk) begin
fast_long_pulse <= fast_long_pulse ^ fast_flag;
end
After the single-shot (fast_long_pulse
) is popped up, the fast_flag
is no longer high on the next clock cycle to cancel itself out.
The next time fast_flag
comes again, it will drop fast_long_pulse
to low. And that falling edge can be picked up by the slower clock as well, as long as it uses the XOR operator.