I get the idea.  This forces the data from domain 1 to sit still on
the data_hold register for at least 2 clock1 periods before it's gated into
out_data on clock2.  That doesn't guarantee with perfect certainty that it
will settle in time, but with any modern register the odds in favor are
extreme.
        I think I did something like this in VHDL about 4 years ago.  The
memories are pretty hazy now, but I think I might have used clocked data
registers, more gates, and fewer flip-flops.  (There are still the handshake
signals to add.)
        Seems like there should be a textbook solution to this.  My second
book on Verilog arrived yesterday, which concentrates on how to apply it
rather than its syntax.  I haven't been into it yet; I'm still reading up on
the language itself.
        I guess the main problem this solves in OGP is that the dotclock
can't synchronize to the host bus handshake, short of adding a complicated
kind of phase-locked loop.  Theoretically doable, I suppose, but
cross-domain data buffering looks a lot easier to implement.



On Tue, Jun 07, 2005 at 04:29:56PM -0400, Timothy Miller wrote:
> The biggest problem with getting data between clock domains is
> metastability.  Metastability can occur where you try to latch a
> signal at time when that signal is in transition.  What we need is a
> reliable means to ensure that one register's Q's are going to meet the
> setup and hold time for another register's D's.  To do this, we store
> data (the payload) in a register in one clock domain and make sure we
> hold it there unchanged long enough to ensure that we can reliably
> store it into a register in the other domain.  To ensure that payload
> data is held long enough, we handshake between the two clock domains
> by, essentially, passing a token back and forth, and when
> metastability affects the token, the worst case is a slight additional
> delay in passing the payload.
> 
> 
> Here's a circuit diagram:
> 
> http://opengraphics.gitk.com/sync.gif
> 
> 
> And here's the source code:
> 
> 
> 
> module sync(
>       in_clock,
>       in_data,
> 
>       out_reset,
>       out_clock,
>       out_data);
> 
> parameter HIGHBIT = 7;
> 
> input out_reset;
> input in_clock, out_clock;
> input [HIGHBIT:0] in_data;
> output [HIGHBIT:0] out_data;
> 
> reg flag_1, flag_2, flag_3, flag_4, flag_5;
> reg [HIGHBIT:0] data_hold, out_data;
> 
> always @(negedge in_clock) flag_1 <= !flag_5;
> 
> always @(posedge in_clock) begin
>      if (!flag_2) data_hold <= in_data;
>      flag_2 <= flag_1;
> end
> 
> always @(negedge out_clock) begin
>     if (out_reset) begin
>         flag_4 <= 0;
>     end else begin
>         flag_4 <= flag_3;
>     end
> end
> 
> always @(posedge out_clock) begin
>     if (out_reset) begin
>         flag_3 <= 0;
>         flag_5 <= 1;
>         out_data <= 0;
>     end else begin
>         flag_3 <= flag_2;
>         flag_5 <= flag_4;
>         if (flag_4 & !flag_5) out_data <= data_hold;
>     end
> end
> 
> endmodule
> 
> 
> 
> 
> 
> Note that the placement of the inverter is somewhat arbitrary.  Since
> inverters are usually free, we can do this.  If the inverter were a
> separate component, it would be better to put it between registers of
> the same clock domain.
> 
> _______________________________________________
> Open-graphics mailing list
> [email protected]
> http://lists.duskglow.com/mailman/listinfo/open-graphics
> List service provided by Duskglow Consulting, LLC (www.duskglow.com)
_______________________________________________
Open-graphics mailing list
[email protected]
http://lists.duskglow.com/mailman/listinfo/open-graphics
List service provided by Duskglow Consulting, LLC (www.duskglow.com)

Reply via email to