Counter Not Testing As Expected? [VHDL]

2019-09-01 14:52发布

I'm trying to make a 32 bit counter in VHDL. Below is my code:

LIBRARY ieee; 
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;

ENTITY counter32 IS 
PORT (en, clk, clr: IN STD_LOGIC; 
count: OUT STD_LOGIC_VECTOR(4 DOWNTO 0)); 

END counter32;

ARCHITECTURE rtl OF counter32 IS 

SIGNAL count_result: STD_LOGIC_VECTOR(4 DOWNTO 0); 

BEGIN
counter32: PROCESS(clk, clr) 

BEGIN 
count <= "00000"; --Initialize counter to all zeroes

IF (clr = '0') THEN 
count_result <= "00000"; 

ELSIF (clk = '1' and clk'EVENT) THEN 

IF (en = '1') THEN
count <= STD_LOGIC_VECTOR(unsigned(count_result) + 1); 
count <= STD_LOGIC_VECTOR(count_result);

 ELSIF (count_result = "11111") THEN
 count_result <= "00000";

END IF; 

END IF; 

END PROCESS counter32;

END rtl;

My test bench code is here:

library ieee; 
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity counter32_tb is
end counter32_tb;

architecture io of counter32_tb is

component counter32 is
port(en,clk,clr:in std_logic; count:out std_logic_vector(4 downto 0)); 
end component;

for all: counter32 use entity work.counter32(rtl);

signal en,clk,clr:std_logic;
signal count:std_logic_vector(4 downto 0);

begin

count <= "00000";
g0: counter32 port map(en,clk,clr,count);

p0: process

begin
en  <= '1';
clk <= '0';
clr <= '1';
wait for 10ns;
en  <= '1';
clk <= '1';
clr <= '1';
wait for 10ns;
en  <= '1';
clk <= '0';
clr <= '1';
wait for 10ns;
en  <= '1';
clk <= '1';
clr <= '1';
wait for 10ns;
en  <= '1';
clk <= '0';
clr <= '1';
wait for 10ns;
en <= '1';
clk <= '1';
clr <= '0';
end process;

end io;

Whenever I test, however, an addition of 1 gives a 'U' STD_LOGIC value and a red bar in testing, as you can see here:

Testing Output

Any idea what the matter is? I'm really confused!

1条回答
该账号已被封号
2楼-- · 2019-09-01 15:00

Any idea what the matter is?

Your waveform doesn't match your test bench stimulus.

There are three assignments to the signal count which appears to show in your waveform (at the test bench level). An initial assignment to "00000", and two conditional assignments. The bouncing back and forth is caused by the process sensitity to clk, bouncing back to "00000" on the following edge of clock using the first assignment statement.

In a process statement the last assignment is the one that takes effect. You're writing it to "00000" and changing that to count_result conditionally based on the positive edge of clock. Note that you aren't actually loading count with count_result + 1 either, the next assignment provides the current value of count_result. While we're on the subject the type conversion to std_logic_vector isn't needed either, count_result is already a std_logic_vector.

The unknown (red) 'flash' at the clock edge is because you haven't actually cleared count_result. The only event on clr is from 'U' to '1' and causes no clear.

The vhdl design code is not functional as a counter.

This:

library ieee; 
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity counter32 is 
    port (
        en, clk, clr: in  std_logic; 
        count:        out std_logic_vector(4 downto 0)
    ); 

end counter32;

architecture rtl of counter32 is 

    signal count_result: std_logic_vector(4 downto 0); 

begin
counter: process(clk, clr) 

    begin 

        if clr = '0' then 
            count_result <= (others => '0'); 

        elsif clk = '1' and clk'event and en = '1' then 

                count_result <= std_logic_vector(unsigned(count_result) + 1); 

        end if;         

    end process;

    count <= count_result;
end rtl;

library ieee;
use ieee.std_logic_1164.all;

entity counter32_tb is
end entity;

architecture foo of counter32_tb is
    signal en:      std_logic:= '0';
    signal clr:     std_logic:= '1';
    signal clk:     std_logic:= '0';
    signal count:   std_logic_vector (4 downto 0);
begin
DUT:   entity work.counter32
    port map (
        en => en,
        clk => clk,
        clr => clr,
        count => count
    );

CLOCK:
    process
    begin 
        wait for 10 ns;
        clk <= not clk;
        if Now > 720 ns then
            wait;
        end if;

    end process;

STIMULUS:
    process
    begin
        clr <= '0';
        en <=  '1';
        wait for 20 ns;
        clr <= '1';
        wait for 20 ns;
        wait for 20 ns;
        wait for 20 ns;
        wait for 20 ns;
        wait for 20 ns;
        en <= '0';
        wait for 20 ns;
        en <= '1';

        wait;
    end process;
end architecture;

Gives this:

counter32 running

The reason no end cases are necessary in the count arithmetic are due to how the unsigned "+" operator works, calling unsigned_add in the package body for numeric_std. End counts are something you need to worry about in scalar increments.

The purpose behind having count (mode out) and count_result, is to allow the count value to be read internally for versions of VHDL predating IEEE Std 1076-2008. For a -2008 compliant simulation you should be only using count. Note the above simulation shown will run on earlier versions of VHDL.

You could likewise make count_result a variable.

And I trust you're aware based on signal array sizes this is a 5 bit counter and not a 32 bit counter. Converting to the latter is relatively easy.

查看更多
登录 后发表回答