Bugs in the clock crossing domain code on the site?

FPGA projects on this site, or abroad

Bugs in the clock crossing domain code on the site?

Postby barawn » Sat Jul 11, 2009 7:43 pm

Hi:

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.
barawn
 
Posts: 4
Joined: Sat Jul 11, 2009 10:47 am

Postby fpga4fun » Thu Jul 23, 2009 5:45 am

I would tend to agree.
For FlagAck_CrossDomain, I took your suggestion as-is and updated the webpage.

For TaskAck_CrossDomain, I propose the following change:
Replace
Code: Select all
always @(posedge clkA) SyncB_clkA <= {SyncB_clkA[1:0], Busyhold_clkB ^ SyncA_clkB[2]};
by
Code: Select all
always @(posedge clkB) if(TaskBusy_clkB & TaskDone_clkB) FlagToggle_clkB <= FlagToggle_clkA;
always @(posedge clkA) SyncB_clkA <= {SyncB_clkA[1:0], FlagToggle_clkB};

What do you think?
fpga4fun
Site Admin
 
Posts: 837
Joined: Thu Sep 18, 2003 6:47 am

Postby barawn » Thu Jul 23, 2009 7:03 pm

Looks good to me.
barawn
 
Posts: 4
Joined: Sat Jul 11, 2009 10:47 am


Return to General projects