1

I have a ring counter which has an enable and a count enable. It so happens that in my larger design, the count enable is synchronous with the clock (and by that I mean the circuit which controls it pulls back to 0 on the rising edge).

Observe:

enter image description here

The F0 and F1 outputs should change at the rising edge happening at t = 130 ns. However, the count_en input gets pulled down at the same time that the ring counter is reading it.

How do I get the correct behaviour from VHDL? Here is my code:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity ring_counter_top is
    Port ( CLK      : in  STD_LOGIC;
              RING_EN   : in  STD_LOGIC;
              COUNT_EN  : in  STD_LOGIC;
           F0           : out STD_LOGIC;
              F1            : OUT STD_LOGIC
             );

end ring_counter_top;

architecture Behavioral of ring_counter_top is
    signal shift_reg : STD_LOGIC_VECTOR(1 downto 0) := "01";
     signal F0_temp : STD_LOGIC := '1';
     signal F1_temp : STD_LOGIC := '0';
     signal count_tmp : std_logic;
begin

     count_tmp <= COUNT_EN;
    -- ring counter
    process (CLK, RING_EN, COUNT_EN)
    begin
     if (RISING_EDGE(CLK)) then
          if (count_tmp = '1') then 
                shift_reg(1) <= shift_reg(0);
                shift_reg(0) <= shift_reg(1);
                F0_temp <= shift_reg(0);
                F1_temp <= shift_reg(1);
          end if;
     end if;
    end process;

     F0 <= F0_temp and RING_EN;
     F1 <= F1_temp and RING_EN;

end Behavioral; 
1
  • 1
    You are assigning the current value of shift_reg and then updating their values. Try including the shift_reg signal in simulation and check its status? If the shift_reg contents are "01" and "10" always, you could just do a negation instead of shifting them. And instead of assigning the shift_reg to F0_temp inside the process, you can assign it to the outputs concurrently. Commented Mar 9, 2018 at 7:50

1 Answer 1

1

The code does exactly what it describes:

at a rising edge of clk:

  • assign the value of shift_reg(0) to shift_reg(1) and F0_temp
  • assign the value of shift_reg(1) to shift_reg(0) and F0_temp

You cannot change the values of a signal within the process (without using time delays, like the wait statements). You can only instruct the simulator to change it at the next delta cycle.

If it is really necessary to change the value within the process, you should use variables instead of signals. But I greatly discourage that, unless you know what you are doing! Variables could pose problems during logic synthesis if used incorrectly.

Just make a small change in your code: switch the initialization values if F1_TEMP and F0_TEMP:

simulation

example code:

library ieee; use ieee.std_logic_1164.all;

entity counter is
    port (
        clk      : in  std_logic;
        count_en : in  std_logic;
        f0       : out std_logic;
        f1       : out std_logic
        );
end entity;

architecture rtl of counter is
    signal shift_reg : std_logic_vector(1 downto 0) := "01";
    signal f0_int : std_logic := '0';
    signal f1_int : std_logic := '1';
begin
    -- ring counter
    process (clk)
    begin
        if rising_edge(clk) then
            if count_en = '1' then 
                shift_reg <= shift_reg(0)&shift_reg(1);
                f0_int <= shift_reg(0);
                f1_int <= shift_reg(1);
            end if;
        end if;
    end process;

    f0 <= f0_int;
    f1 <= f1_int;
end architecture;

library ieee; use ieee.std_logic_1164.all;
entity counter_tb is end entity;
architecture behavioral of counter_tb is
    signal clk, count_en, f0, f1 : std_logic := '0';
begin
    dut: entity work.counter port map(clk, count_en, f0, f1);

    clk <= not clk after 10 ns;

    count_proc: process begin
        count_en <= '0';
        wait for 99 ns;
        wait until rising_edge(clk);
        count_en <= '1';
        wait until rising_edge(clk);
        count_en <= '0';
        wait;
    end process;
end architecture;

Edit:

A VHDL simulator operates in two alternating phases:

  1. statement execution, where triggered statements (such as the process statement) are evaluated and events (like signal assignment) are put in a queue
  2. event processing, where the events in the queue are processed.

Thus if x is a signal and you write x <= y; in a process, then the value of x will not immediately change: it will only be queued. All actual assignments are not processed until the next delta cycle, which will occur after a time delay: In this case after the process is fully evaluated, as there is no wait statement. In testbenches, you can have multiple wait statements in one process, which will induce time delay and hence trigger assignment.

Even more in detail: in application. Say:

entity foo is end entity;
architecture bar of foo is
    signal x : bit := '1';
    signal y : bit;
begin
    process begin
        x <= '0';
        y <= x;
        wait;
    end process;
end architecture;

After simulation end (1-2 delta cycles) x will be '0' and y will be '1', because the assignment of '0' to x will not occur until The next delta cycle, This will occur at the infinite wait statement in this case, because a time delay is introduced.

Sign up to request clarification or add additional context in comments.

2 Comments

What do you mean by "you cannot change a signal withhin a process"? Which signal are you talking about, the count enable in the simulation (I'm using Quartus's waveform editor)? Also, how is your code different? It is making the exact same assignments as mine in the princess statement, even though it has different syntax.
@Mahkoe First question: see my edit. Second question: No, not exactly the same: I switched the initialization values of F0 and F1.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.