VHDL: Issues With Asynchronous Signals and Inferred Laches
by Jason63 on Nov 17, 2011 |
Jason63
Posts: 2 Joined: Apr 7, 2011 Last seen: Jun 30, 2016 |
||
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 what is going on, but I'm not sure if there is a better way to do it. Here is the relevant code snippet: -- 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 '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 /= 65536 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 problem 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: 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 '0'); count_h := (others => '0'); else if count /= 65536 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 original (synchronous) code also has a the same inferred latches in it 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. Now the first piece of code 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 noticed any problems. However, I would love to know how to get rid of the inferred latches which everyone tells me are evidence of bad design. I'm even more curious as to what is going on in the second piece of code that is causing the glitches I describe above and how it might be fixed. -- Jason |
RE: VHDL: Issues With Asynchronous Signals and Inferred Laches
by Jason63 on Nov 18, 2011 |
Jason63
Posts: 2 Joined: Apr 7, 2011 Last seen: Jun 30, 2016 |
||
My apologies for the errors in formatting in the above code. The forum software here doesn't support [code] tags so I attempted to format the code using HTML, and I see that is has messed up portions of the code as a result. In particular, the first if statement in both code snippets should look like this: 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'); Where I've replace the signal assignment characters with {= so that they are not mis-interpreted as HTML. Also, the constant 65536 should be 65535 -- that was a typo on my part. Sorry for any confusion I may have cause from this. -- Jason |