Electronic – VHDL: How to only update register at rising edge of the clock

clockcounterprocessvhdl

I have a counter called lastelem_reg. At the rising edge of each clock, it should check whether another signal enqueue is HIGH. If it is, then lastelem_reg will be incremented by 1 in the next clock, otherwise it continues to hold its old value. This seems like a very simple problem, but I'm not getting the intended behavior. Here's the VHDL code:

    process(clk,reset)
    begin
        if (reset='1') then
            lastelem_reg    <= (others=>'0');
        elsif (rising_edge(clk)) then
            lastelem_reg    <= lastelem_next;
        end if;
    end process;
    
    
    process(lastelem_reg)
    begin
        if (enqueue = '1') then
            lastelem_next <= lastelem_reg + 1;
        else
            lastelem_next <= lastelem_reg;
        end if;
    
    end process;

Simulating the above code, results in the waveform shown below. We see that lastelem_reg never gets updated.
enter image description here

So, I thought let's add enqueue to the sensitivity list of the second process and see what we get. The waveform is shown below. We see two things happening here that not supposed to happen. First, the lastelem_next signal changes twice every clock cycle, which shouldn't be happening. Second, the lastelem_reg is updating 1 clock before it should. For example, at 10ns, when the first enqueue signal comes, lastelem_reg should be 0, but here it is 1.

Any idea how to overcome this issue ?
enter image description here

Best Answer

Forget using combinational processes with complicated and error-prone sensitivity lists, until the once-in-a-blue-moon time you actually need them.

Especially when you move on to state machines; but even here, a single synchronous process is cleaner and shorter, as well as much easier to get right. This reproduces the code you have (with the correction to the sensitivity list)

process(clk,reset)
begin
    if reset='1' then
        lastelement     <= (others=>'0');
    elsif rising_edge(clk) then
        if enqueue = '1' then
            lastelement <= lastelement + 1;
        end if;
    end if;
end process;

There is one additional wrinkle in your problem specification however:

At the rising edge of each clock, it should check whether another signal enqueue is HIGH. If it is, then lastelem_reg will be incremented by 1 in the next clock, otherwise it continues to hold its old value.

This needs an additional single cycle delay:

process(clk,reset)
begin
    if reset='1' then
        lastelement     <= (others=>'0');
        lastelement_d1  <= (others=>'0');
    elsif rising_edge(clk) then
        if enqueue = '1' then
            lastelement <= lastelement + 1;
        end if;
        lastelement_d1  <= lastelement;
    end if;
end process;

and I think lastelement_d1 (lastelement delayed 1 cycle) is what you are looking for.