VHDL variable behaving strangely

fpgaintel-fpgaquartus-iivhdl

I have the following snippet of VHDL code which is misbehaving and I don't know why:

process (clock)

variable counter : std_logic_vector (15 downto 0) :=  x"0000";
variable op : std_logic_vector (7 downto 0);

begin

if (clock = '1') then

    op := cw (15 downto 8);

    -- This if statement is misbehaving 
    if (op = x"20") then
        counter  := counter + cw (7 downto 0);
    end if;

    counter := counter + 2;

    ia <= counter;

    end if;

end process;

As the simulation shows, the code increments in counts of 2, but the cycle after the if statement, weird things happen

Simulation

Sorry, the top waveform is the clock, then "cw" and "ia" at the bottom

EDIT: The code is supposed to count up by 2 by default. If the upper byte of "cw" is 0x20, then it is incremented by 2 and another number

Best Answer

You don't say what you want the code to do, but I can see a couple of trouble areas. The first is that you don't have any reset logic in your process. It's important to make sure that you properly initialize everything in order to prevent unusual operation. This however is not likely the cause of your trouble.

What I think is causing the incorrect operation is that you are looking for the clock signal to be high instead of checking for the clock to transition from a low to high. This is called the "rising edge" of the clock. Synchronous logic operates on clock edges rather than clock levels.

You mention that you should not have to look for a rising edge since the clock is in the sensitivity list, and thus if your process is executed you can only check the level of the clock. This may be theoretically true but synthesis tools work by inferring logic from the language used to describe it. Most synthesis tools I have used are designed to produce correct logic when described below.

process(clock, reset)

variable counter : std_logic_vector (15 downto 0) :=  x"0000";
variable op : std_logic_vector (7 downto 0);

begin

if reset = '1' then
    -- reset everything to a known state here

elsif rising_edge(clock) then
    op := cw(15 downto 8);

    if op = x"20" then
        counter := counter + cw(7 downto 0);
    end if;

    counter := counter + 2;
    ia <= counter;
end if;
end process;

Writing good HDL is just as much about getting the logic correct as it is describing it in the way the synthesis tools are expecting to see it. If you decide "it's the same thing" and write things in a non-standard way you may well find that the simulator tells you one thing but the synthesizer fails to see it the same way. This is a fine point to learn, and one that can cause you a lot of headache and frustration should you decide otherwise.