Search code examples
vhdlquartus

Error (10818): Can't infer register for ... at ... because it does not hold its value outside the clock edge


I´m trying to verify four buttons. When one of them are pushed I need to check if the corresponding led are lit. So, I did the code, where a process checks which button has been pressed and compares the values with the value of the led (lit or not). The problem occurs when I want to increase the variable that controls the amount of hits (successes) of the player.

Remembering that "acertos" is a signal of the type std_logic_vector(3 downto 0)

process(pb0,pb1,pb2,pb3)
    variable erro_int   : STD_LOGIC;
begin
    if (clk_game = '0') then
        erro_int:='0';
        if rising_edge(pb0) then
            if pb0 /= led(0) then 
                erro_int:='1';
            end if;
        elsif rising_edge(pb1) then
            if pb1 /= led(1) then 
                erro_int:='1';
            end if;
        elsif rising_edge(pb2) then
            if pb2 /= led(2) then 
                erro_int:='1'; 
            end if;
        elsif rising_edge(pb3) then
            if pb3 /= led(3) then 
                erro_int:='1'; 
            end if;
        else    
            acertos <= acertos+1;
        end if;
    end if;
end process;

Solution

  • See Error (10818): Can't infer register for “E” at clk200Hz.vhd(29) because it does not hold its value outside the clock edge which demonstrates the exact same Error case. Normally you'd also be encouraged to use the vendor as a resource for their error messages as well.

    The error case here is expressing that the acertos assignment is not taking place inside a conditional assignment statement dependent on a signal event used as a clock.

    However this isn't the end to potential problems you'll likely encounter with the process you've shown us from some design specification.

    There's the question of whether signals pb0, pb1, pb2 and pb3 are de-bounce filtered. See Wentworth Institute of Technology Department of Electronics and Mechanical ELEC 236 Logic Circuits Switch Debounce Design, where the first scope trace shows a normally pulled high, momentary switch connecting to ground switch input. The issue is contact bounce. The web page talks about some solutions.

    De-bounce would allow you to use your button inputs as clocks but there are other issues in your process.

    For instance some vendors won't accept multiple clocks in the same process statement, your design specification may not be portable.

    There isn't a recognized sequential event inferring storage element construct that allows multiple clocks for the same storage element (erro_int). Because there is no passage of simulation time expressed by successive if statements without inter-dependencies you might expect that perhaps only the last one get's expressed as hardware.

    You could combine all the push buttons into a single signal:

    button_press <= not (not pb0 and not pb1 and not pb2 and not bp3);
    

    Where any button pressed can cause an edge event when transitioning from no buttons pressed.

    If you de-bounce this say using a counter and testing for successive events you could use it as the sole clock.

    Let's assume for the following it's de-bounced. Setting a default value in the process statement for erro_out would give you a process that looks something like:

    process(button_press)
        variable erro_int: std_logic;
    begin
        if (clk_game = '0') then
            erro_int:='0';
            if rising_edge(button_press) then
                if pb0 /= led(0)  or pb1 /= led(1) or pb1 /= led(2) or pb3 /=pb3 then 
                    erro_int:= '1';
                end if;
            acertos <= acertos + 1;
        end if;
    end process;
    

    (And I looked up the translation of acertos - hits, not necessarily valid hits, I take it this is a game.)

    This still doesn't solve the issue that erro_int is a local variable. If it's used elsewhere it wants to be a declared as a signal. If you change the process to:

    ...
    signal erro_int:   std_logic;  -- defined say as an architecture declarative item
    ...
    
    process(button_press)
    begin
        if (clk_game = '0') then
            erro_int <='0';
            if rising_edge(button_press) then
                if pb0 /= led(0)  or pb1 /= led(1) or pb1 /= led(2) or pb3 /=pb3 then 
                    erro_int <= '1';
                end if;
            acertos <= acertos + 1;
        end if;
    end process;
    

    You can use it externally. The reason why this works is that a process only has a single driver for a signal and the last assignment at the current simulation time is the one that takes effect (there's only one assignment to the current simulation time).

    And of course if you use a clock to de-bounce you could use button_press as an enable if it were gated to only last one clock.