Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
16 years ago

Clock domain crossing of a gray counter. Any constraints / directives / cells?

I have two unrelated clock domains 50MHz / 133MHz

> reg clk50;

> reg clk133;

I am implementing a Fifo between two clock domains.

and have gray counters crossing the clock domains.

> reg [13:0] grayctr133; // e.g. write pointer

> reg [13:0] grayctr50; // e.g. readpointer

In order to determine whether the fifo is full / empty I have to compare both gray counters

so I thought about

> reg [13:0] grayctr133_retimed50;

> reg[13:0] grayctr50_retimed133;

> always @(posedge clk50) begin

> grayctr133_retimed50;

> emtpy <= (grayctr50 == grayctr133_retimed50) & wasreading;

> end

My question:

1.) Will this work reliably or would I need double retiming before I could do the comparison?

2,) What is the correct way to tell the Quartus, that timing violations between grayctr133_retimed50

and grayctr133 can be ignored. Are there pragmas, that I can add directly into the RTL or do

I have to add statements into the a constraint file / the synthesis script

If both is possible, what would you recommend?

4 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    How come you're not using the Megafunction FIFO? I ask, because it's been used/tested in many, many designs. (I really don't know of any designs that don't use it). Asynch FIFOs are a very difficult thing to design, and unless you've been studying for a long time and know all the ins and outs, will probably not work with high reliability. You may have a good reason, but make sure it balances out with the risk.

    What do you mean compare the counters? If you're checking if they're equal, it's usually too late. By the names, I'm guessing your counters run at different frequencies, like 50MHz and 133MHz. So it's possibly to get 2 clocks of the faster clock before the slower clock has a chance to respond. The Megafunction FIFO, for example, will often raise a full/empty flag early, just to make sure it doesn't under/overflow. If no other read/writes are in the pipe, that flag will go low and allow the user to finish out their reads/writes. (Note that this doesn't happen often, but under the right circumstances it does, and I've seen people complain about it, but the fact is that this is the correct behavior).

    And I wouldn't compare signals from two different clock domains. I know they're gray coded, but worry about that really working. I think the counters are usually gray coded and then passed into the other domain through a series of metastability registers before they are compared. (With gray counts, I don't think there's an easy way to do less than or greater than checks, just equals, so the actual compares may be binary comparisons, but that's only once the gray code value has been properly passed to the other domain).

    Of course, creating your own FIFO for your own application may be a lot easier, if you know how it's supposed to operate. For example, if your FIFO is 128 deep, and you know you'll burst in exactly 128 and burst out exactly 128 at a time, and there's a determined space between bursts, then you don't need to compare counts, just make sure one side has passed a calculated threshold before the other side burst occurs. That's just an example, but if you can shape the behavior of your reads and writes, it might make the FIFO designing a lot easier.

    In TimeQuest, you can do a set_false_path between domains in the .sdc. I don't think this is supported yet within the code(it was for TAN, and should be coming for TQ I imagine).
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi Rysc,

    Thanks for your answer:

    The reason why I don't use the mega functions:

    - I don't know quartus that well

    - I'd like to learn

    - I'd like to implement a Fifo, that can be used with Altera, Xililnx and perhaps even with Silicondesign flows and the minimum of `ifdefs / specific blocks

    For my use case comparing the values would be good enough.

    The write pointer is controlled by the same clock domain as the full flag, so having a delayed version of the read pointer would only pretend, that the Fifo were fuller than it really is.

    The read pointer is controlled by the same clock domain as the empty flag, so having a delayed version of the write pointer would only pretend, there's less data to fetch there really is.

    if I really had to perform write / read pointer calculus, then I could perform a gray to normal conversion and perform the comparisons or other arithmetics.

    My main difficulties are:

    - do I need double retiming for gray counters / are there any special cells / coding styles for resynchronizing flip flops between two clock domains

    In case of doubt I would just double retime, the counter bits.

    - where and how do I specify the constraints.

    Currently I used quartus to create a project, selected the target device,

    added all verilog sources.

    I then perform the compilation via

    quartus_sh --flow compile

    How to and whre can I add constraints to ignore signals crossing clock domains (or is there something like a global switch to say:

    "Please ignore ALL transitions between clock1 and clock2 ?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Use TimeQuest. (You might be using TAN, which I recommend against.) Read the manual about TimeQuest first. Create an .sdc file with:

    derive_pll_clocks -constrain_base_clocks

    derive_clock_uncertainty;# (This line should be in there if targeting a 65nm or smaller device)

    To cut the paths, either:

    set_false_path -from *grayctr133 -to *grayctr50

    set_false_path -from *grayctr -to *grayctr133

    To do all paths between domains, do:

    set_clock_groups -asynchronous -group {clk50} -group {clk133}

    where the clock names come from what was created with derive_pll_clocks. This is most easily found when running the Report Clocks task in TimeQuest.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Thanks I'll do some reading.

    Currently I just created a quartus project, added all verilog sources and started compiling with quartus_sh --flow compile

    I even don't know what I'm using in the moment ( TAN or Timequest )