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)