I've been using the clock crossing domain code (signal sync, flag sync, task sync) on the site for a while now, and I'm pretty sure I've found at least one bug, and one case where the behavior probably isn't ideal.
In TaskAck_CrossDomain, there's this code:
- Code: Select all
always @(posedge clkA) SyncB_clkA <= {SyncB_clkA[1:0], Busyhold_clkB ^ SyncA_clkB[2]};
The problem here is that Busyhold_clkB and SyncA_clkB[2] are both synchronous to the clock B domain, and a combination of them are being latched in the clock A domain. Given signal skew between Busyhold_clkB and SyncA_clkB[2] (which there will be some) there will always be a window where clkA can latch the wrong value, and generate a false Ack flag.
Not really sure the best way to fix this: after I found this bug causing problems in my design, I went back and looked at what I actually needed and wrote a different module anyway. But I just wanted to point it out, since it's definitely not correct. It works "mostly" - depending on the skew between the two lines - but it's definitely too dangerous to use.
The other "bug" is in the FlagAck_CrossDomain module. Note here:
- Code: Select all
always @(posedge clkA) SyncB_clkA <= {SyncB_clkA[0], SyncA_clkB[1]};
assign FlagOut_clkB = (SyncA_clkB[2] ^ SyncA_clkB[1]);
assign Busy_clkA = FlagToggle_clkA ^ SyncB_clkA[1];
It depends on what you define as "received the flag" here - most people, I think, would say that clkB has received the flag at the first rising edge where clkB sees a positive FlagOut_clkB.
But that's not what happens here: since SyncB_clkA is derived from SyncA_clkB[1], it sends a flag back to clkA when the flag first goes high. If clkB is faster than clkA, clkB may not have latched the flag when Busy goes low.
This fix is easy: it's just
- Code: Select all
always @(posedge clkA) SyncB_clkA <= {SyncB_clkA[0],SyncA_clkB[2]};
This guarantees that when Busy goes low, clkB has latched the flag.