David Poole
David Poole

Reputation: 3510

VHDL Counter result giving X

I am attempting to build a counter in VHDL. Eventual goal is to hook the "do_count" to a button. The total will be converted to BCD and displayed on a 7-segment display. Push the button, watch the numbers increment.

I'm using ModelSim and I can see the internal "counter_value" correctly increment by 1. But the output signal "total" becomes "000X" then "00X0" during my two test "do_count"s. Why am I getting an X'd signal?

I've moved the "output <= current_value" around inside the process, outside the process, inside the 'if's, etc. Still the "000X".

I've tried using a variable 'tmp' inside the process.

count_up : process(clk) is
   variable tmp : unsigned (15 downto 0 );
begin
   tmp := current_value;
   -- snip
   if do_count='1' then
      current_value <= tmp + to_unsigned(1,16);
   end if;

Still I get the "000X".

Full code:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;

entity d_counter is
    port ( rst : in std_logic;
           clk : in std_logic;
           do_count : in std_logic;
           total : out unsigned (15 downto 0)
        );
  end entity d_counter;

architecture counter_arch of d_counter is
  signal current_value : unsigned (15 downto 0) := (others=>'0');
begin
  count_up : process(clk) is
  begin
    if rst='1' then
      current_value <= (others=>'0');
      total <= (others=>'0');
    elsif rising_edge(clk) then
      if do_count='1' then
        current_value <= current_value + to_unsigned(1,16);
      end if;
    end if;
  end process count_up;
  total <= current_value;
end architecture counter_arch;

Testbench:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;

entity test_counter is 
  begin
  end entity test_counter;

architecture run_test_counter of test_counter is

  signal t_rst : std_logic := '1';
  signal t_clk : std_logic := '0';
  signal t_do_count : std_logic;
  signal t_total : unsigned( 15 downto 0 );

  component d_counter is
    port ( rst : in std_logic;
           clk : in std_logic;
           do_count : in std_logic;
           total : out unsigned( 15 downto 0 )
        );
  end component d_counter;

begin
  uut : d_counter
    port map( rst => t_rst,
      clk => t_clk,
      do_count => t_do_count,
      total => t_total );

    clock : process is 
    begin

        t_clk <= '0'; wait for 10 ns;
        t_clk <= '1'; wait for 10 ns;
    end process clock;

    stimulus : process is
    begin
      t_rst <= '1';
      t_do_count <= '0';
      t_total <= (others =>'0');
      wait for 15 ns;

      t_rst <= '0';
      wait for 10 ns;

      t_do_count <= '1';
      wait for 10 ns;

      t_do_count <= '0';
      wait for 10 ns;

      t_do_count <= '1';
      wait for 10 ns;

      t_do_count <= '0';
      wait for 10 ns;

      wait;

    end process stimulus;
end architecture run_test_counter;

Update 03-Oct-2012. BOTH the answers helped. Moving "total <= current_value" inside the process (From @simon) and removing the extra "t_total <= (others =>'0');" (From @peter-bennett) in my testbench was required. I had to do both to get rid of the X's.

Upvotes: 2

Views: 7522

Answers (2)

Peter Bennett
Peter Bennett

Reputation: 633

It looks like your mistake is in your testbench. The signal t_total is mapped to the total output of your counter component, yet you are writing to it with the t_total <= (others => '0') assignment. If you remove this I think your problem will go away.

  uut : d_counter
    port map( rst => t_rst,
      clk => t_clk,
      do_count => t_do_count,
      total => t_total );

    clock : process is 
    begin

        t_clk <= '0'; wait for 10 ns;
        t_clk <= '1'; wait for 10 ns;
    end process clock;

    stimulus : process is
    begin
      t_rst <= '1';
      t_do_count <= '0';
      t_total <= (others =>'0'); <-- Do not assign to t_total (its an output)

Upvotes: 3

Khanh N. Dang
Khanh N. Dang

Reputation: 906

Your code write multi-driven with "total". You should delete assigment in process count_up.

count_up : process(clk) is
  begin
    if rst='1' then
      current_value <= (others=>'0');
      total <= (others=>'0');  --> Remove it
    elsif rising_edge(clk) then
      if do_count='1' then
        current_value <= current_value + to_unsigned(1,16);
      end if;
     end if;
  end process count_up;

  total <= current_value; -- Keep it

Upvotes: 3

Related Questions