Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

VHDL: Question About Asynchronous Signals and Inferred Laches

Status
Not open for further replies.

jason63

Newbie level 3
Joined
Nov 17, 2011
Messages
3
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,323
Hi,

I've written some code for a CPLD to perform the functions of a frequency counter. The code is working fine, but I'm getting some warnings about inferred latches. I understand why the compiler is generating the latches, but I'm wondering if there is a better way to do it. Here is the relevant code snippet:

Code:
-- port ( fin : in STD_LOGIC );				-- signal to be measured
-- signal clk_gate STD_LOGIC;				-- gate clock
-- signal count_shadow_l UNSIGNED(15 downto 0);		-- holds last full value of count
-- signal count_shadow_h UNSIGNED(15 downto 0);

process(fin,clk_gate)
    variable clk_edge : STD_LOGIC := '1';			-- edge detection
    variable count_l : UNSIGNED(15 downto 0);
    variable count_h : UNSIGNED(15 downto 0);
        begin
        if (clk_gate='1' and clk_edge='1') then
            clk_edge :='0';				-- only reset once per gate period
            count_shadow_l  <= count_l;			-- save current count
            count_shadow_h <= count_h;
            count_l := (others => '0');			-- reset counter
            count_h := (others => '0');
        elsif (clk_gate='0' and clk_edge='0') then
            clk_edge := '1';				-- enable edge detection
        elsif rising_edge(fin) then
            if count /= 65535 then
                count_l := count_l + 1;      		-- increment low word
            else
                count_l := 0;
                count_h := count_h + 1;			-- increment high word
            end if;
        end if;
end process;

The compiler warns me that clk_edge and count_shadow_* have inferred latches associated with them, but I actually want this behavior. The issue stems from the fact that I'm dealing with two asynchronous inputs and I need to change one output in response to one input, but not the other. Otherwise I would just split it apart into two separate processes.

I initially tried to write the code to be synchronous with the input fin like this:

Code:
process
        variable clk_edge : STD_LOGIC := '1';
        variable count_l : UNSIGNED(15 downto 0);
        variable count_h : UNSIGNED(15 downto 0);	
        begin
            wait until rising_edge(fin);
                if (clk_gate='1' and clk_edge='1') then
                    clk_edge := '0';
                    count_shadow_l  <= count_l;
                    count_shadow_h <= count_h;
                    count_l := (others => '0');
                    count_h := (others => '0');
                else
                    if count /= 65535 then
                        count_l := count_l + 1;
                    else
                        count_l := 0;
                        count_h := count_h + 1;
                    end if;
                    if (clk_gate='0' and clk_edge='0') then
                        clk_edge := '1';
                    end if;
                end if;
end process;

But when I did this, I noticed that occasionally count_h would not be reset in initial if statement. I discovered this by hooking up a logic analyzer to the output and could see that every now and then count would fail to reset to zeros at the same time clk_edge was set to '0' (clk_edge was always set to '0' successfully).

I realize that the second block of code above also has a the same inferred latches in it to the first and that perhaps this is related to the above not always working correctly, but it's not clear to me how to eliminate them because I can't change count_shadow_* in the outermost else statement and count_h should only change when count_l rolls over.

The first code snippet works fine with the inferred latches -- I've run it for extended periods of time with the logic analyzer set to trigger on any failures and I never seen any. However, I would love to know how to get rid of the inferred latches which I have read are evidence of bad design. I'm even more curious as to what is going on in the second block of code that is causing the glitches I describe above and how it might be fixed.

--
Jason
 

you should synchronise any asynchronous input with at least a double register. Then you can run everything inside standard clock domain. Gated clocks are not recommended for FPGAs/CPLDs. It is best to stick to synchronous designs.
 

you should synchronise any asynchronous input with at least a double register. Then you can run everything inside standard clock domain. Gated clocks are not recommended for FPGAs/CPLDs. It is best to stick to synchronous designs.

Thanks for your reply.

Could you give me an example of how this would work? In the case of the code above, the asynchronous input (signal whose frequency is to be measured) runs many times faster than any synchronous clock in the system. The gate clock runs at 1 to 100 Hz, but fin can run at 50 MHz or more.

--
Jason
 

you cannot synchronise a signal that is running at 50Mhz. You need a system clock at least as fast as your external signal.
 

Both your designs are asynchronous state machines that have absolutely no guarantee to work.

The main problem is the following lines:

Code:
               if (clk_gate='1' and clk_edge='1') then
                    clk_edge := '0';
As soon as the "if" is true, it will become false again. This means that the rest of the statements in that "if" clause are controlled
by a very short pulse. You have no control over the length and there is no guarantee that it is detected by all logic.
This is why your second code example failed, but your first example can fail in the same way. You have no guarantee.

You should avoid asynchronous state machines like this. They can work but you will get no help from the tools,
so you must know exactly what you are doing.

Because of the high frequency of "fin", you probably need two clock domains in the design, "fin" and the system clock.

To make sure that the real circuit behaves as the simulation, follow some rules:

1. No asynchronous state machines unless you can prove they are safe.
2. All clocked processes based on the standard template
3. Syncronize all signals that enter a clock domain.

The frequency counter is a non-trivial task, especially if "fin" is allowed to go down to 0 Hz.

Why the "high word" / "low word"? With your code, the maximum frequency will be the same for one long counter.
Also remember that "unsigned" will wrap to zero automatically.
 
you cannot synchronise a signal that is running at 50Mhz. You need a system clock at least as fast as your external signal.

The Flancter

I ran into this a while back, I wonder if something like this would work?
 
Both your designs are asynchronous state machines that have absolutely no guarantee to work.

The main problem is the following lines:

Code:
               if (clk_gate='1' and clk_edge='1') then
                    clk_edge := '0';
As soon as the "if" is true, it will become false again. This means that the rest of the statements in that "if" clause are controlled
by a very short pulse. You have no control over the length and there is no guarantee that it is detected by all logic.
This is why your second code example failed, but your first example can fail in the same way. You have no guarantee.

Yes, I see this issue and don't see an obvious solution within my existing framework as the problem is a recursive one.

You should avoid asynchronous state machines like this. They can work but you will get no help from the tools,
so you must know exactly what you are doing.

Because of the high frequency of "fin", you probably need two clock domains in the design, "fin" and the system clock.

To make sure that the real circuit behaves as the simulation, follow some rules:

1. No asynchronous state machines unless you can prove they are safe.
2. All clocked processes based on the standard template
3. Syncronize all signals that enter a clock domain.

How does one prove an asynchronous state machine is safe?

Given that fin should be able to go as fast as the logic will allow (well over 100MHz), are there any standard approaches to implementing a frequency counter I could examine?

If I understand what you are saying, then if fin is expected to be much faster than clk_gate, I should be synchronizing the clk_gate signal to the fin clock domain rather than the other way around. This precludes me from counting signals that are less than half the period of clk_gate, but that is not a problem for what I want to do. This seems like it would be a good direction for me to try.

Thank you for your comments.

---------- Post added at 23:42 ---------- Previous post was at 23:39 ----------

The Flancter

I ran into this a while back, I wonder if something like this would work?

Now that looks like a very interesting circuit. I'm not sure whether or not it will solve my problem, but it is definitely something I'd like to take a closer look at. Thanks for pointing it out.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top