Search code examples
if-statementvhdlcounter

if statement inside counter in VHDL


I have a 3 bit counter that counts upwards from "000". Every time "101" is reached, I want the o_en signal to be HIGH.
I have the following VHDL file.
The behaviour is unfortunately different.
The o_en signal is HIGH, when "110" is reached (delayed by one clock cycle).

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity special_counter is
    port(
        i_clk : in std_logic;
        i_en : in std_logic;
        i_rst : in std_logic;
        o_data : out std_logic_vector(2 downto 0);
        o_en : out std_logic
    );
end entity;

architecture behave of special_counter is
signal w_data : std_logic_vector(2 downto 0);
signal w_en : std_logic;

begin
    process(i_clk, i_rst) begin
        if i_rst = '1' then
            w_data <= "000";
        elsif rising_edge(i_clk) then
            if i_en = '1' then
                if w_data = "101" then
                    w_en <= '1';
                    w_data <= w_data + 1;
                else
                    w_en <= '0';
                    w_data <= w_data + 1;
                end if;
            end if;
        end if;
    end process;
    o_data <= w_data;
    o_en <= w_en;
end architecture;

How can I change my program to perform the expected behaviour ?


Solution

  • That is exactly correct and that is what you have coded.

    To put it into words: "At the rising edge of the clock, when the counter has the value 101 then the w_en will be set high."

    Thus the w_en signal from which o_en is derived, will be high after the rising edge of the clock.
    In the same time as the w_data changes and after the rising clock becomes "110".

    There are two solutions:

    1. Test for "100" (so one cycle sooner)

    2. Make w_en (and thus o_en) combinatorial.

    For the latter you must move the assignment outside the 'clocked' section and use e.g.

    w_en <= '1' when w_data = "101" else '0';