简体   繁体   中英

How can I add a maximum value to my bidirectional 4bit counter (loop)?

I have this code which is a bidirectional counter that loops around.

I now want to add an input (maybe from switches or something), which controls the maximum value of the counter, for example if the max value from the input is "0111" the counter will count up to 0111 and then loop back around to 0000, and if the counter is counting down to 0000 it will loop back to 0111. I'm getting a bit confused on how/where I should do this because I've used nested ifs to implement an enable and reset input.

Here is the code:

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

entity UPDOWN_COUNTER is
    Port ( clk: in std_logic; -- clock input
           reset: in std_logic; -- reset input 
           up_down: in std_logic; -- up or down
            enable: in std_logic; -- enable

            max: in std_logic_vector(3 downto 0); -- max value counter 

           counter: out std_logic_vector(3 downto 0) -- output 4-bit counter
     );
end UPDOWN_COUNTER;

architecture Behavioral of UPDOWN_COUNTER is
signal counter_updown: std_logic_vector(3 downto 0);
begin
process(clk,reset,enable,max)
begin
if(enable ='1') then
if(rising_edge(clk)) then
    if(reset='1') then
         counter_updown <= x"0";
    elsif(up_down='1') then
         counter_updown <= counter_updown - x"1"; -- count down 
    else 
         counter_updown <= counter_updown + x"1"; -- count up
    end if;
  end if;
 end if;
end process;

 counter <= counter_updown;

end Behavioral;

Here is the test bench:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity tb_counters is
end tb_counters;

architecture Behavioral of tb_counters is

component UPDOWN_COUNTER 
    Port ( clk: in std_logic; -- clock input
           reset: in std_logic; -- reset input 
           up_down: in std_logic; -- up or down input
            enable: in std_logic; -- enable input
            max: in std_logic_vector(3 downto 0); -- max value counter 
           counter: out std_logic_vector(3 downto 0) -- output 4-bit counter
     );
end component;
signal reset,clk,enable,up_down: std_logic;
signal max,counter:std_logic_vector(3 downto 0);

begin
dut: UPDOWN_COUNTER port map (clk => clk, reset=>reset,enable => enable, up_down => up_down, max => max,counter => counter);
   -- Clock 
clock_process :process
begin
     clk <= '0';
     wait for 10 ns;
     clk <= '1';
     wait for 10 ns;
end process;

stim_proc: process
begin        

    max <= "1000"; -- Test value for Counter max value
    enable <= '1'; 
     reset <= '1';
   up_down <= '0';
    wait for 20 ns;    
    reset <= '0';
  wait for 300 ns;    
  up_down <= '1';
  --
  wait for 50 ns;
  enable <= '0';
  wait for 50 ns;
  enable <= '1';
   wait;
end process;
end Behavioral;

You've specified a synchronous reset. There's at least one synthesis issue, where enable is inferred to gate the clock. The numeric package has been switched to ieee.numeric_std in the following (the example can be modified for the non-standard Synopsys numeric package):

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

entity updown_counter is
    port ( 
        clk:        in  std_logic;
        reset:      in  std_logic;
        up_down:    in  std_logic;
        enable:     in  std_logic;
        max:        in  std_logic_vector(3 downto 0); 
        counter:    out std_logic_vector(3 downto 0) 
     );
end entity updown_counter;

architecture behavioral of updown_counter is
    signal counter_updown:  unsigned(3 downto 0);
begin
    process (clk) -- other signals evaluated inside clock edge
    begin
        if rising_edge(clk) then
            if enable = '1' then  -- don't gate the clock
                if reset = '1' then
                    counter_updown <= (others => '0');
                elsif up_down = '1' then             -- down
                    if counter_updown = 0 then
                        counter_updown <= unsigned(max);
                    else
                        counter_updown <= counter_updown - 1;
                    end if;
                else -- count up
                    if counter_updown = unsigned(max) then
                        counter_updown <= (others => '0');
                    else
                        counter_updown <= counter_updown + 1;
                    end if;
                end if;
            end if;
        end if;
    end process;
     counter <= std_logic_vector(counter_updown);
end architecture behavioral;

And that gives:

tb_counters.jpg

with your testbench.

This is the similar to @user1155120's answer (which I recommend you accept as the answer), but I've used an asynchronous reset instead. Also added a generic to specify the number bits in the counter.

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

entity UpdownCounter is
    generic
    (
        COUNTER_BITS: natural := 4
    );
    port
    (
        clk: in std_logic; -- clock input
        reset: in std_logic; -- reset input
        up_down: in std_logic; -- up or down input
        enable: in std_logic; -- enable input
        max: in std_logic_vector(COUNTER_BITS - 1 downto 0); -- max value counter
        counter: out std_logic_vector(COUNTER_BITS - 1 downto 0) -- output N-bit counter
     );
end UpdownCounter;

architecture V1 of UpdownCounter is
    signal counter_updown: unsigned(COUNTER_BITS - 1 downto 0);
begin
    process(clk, reset)
    begin
        if reset then
            -- Do asynchronous reset.
            counter_updown <= (others => '0');
        elsif rising_edge(clk) then
            -- Do synchronous stuff.
            if enable then
                if up_down then
                    -- Count down to zero cyclically.
                    if counter_updown = 0 then
                        counter_updown <= unsigned(max);
                    else
                        counter_updown <= counter_updown - 1;
                    end if;
                else
                    -- Count up to max cyclically.
                    if counter_updown = unsigned(max) then
                        counter_updown <= (others => '0');
                    else
                        counter_updown <= counter_updown + 1;
                    end if;
                end if;
            end if;
        end if;
    end process;

    counter <= std_logic_vector(counter_updown);

end V1;

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

entity UpdownCounter_TB is
end UpdownCounter_TB;

architecture V1 of UpdownCounter_TB is

    component UpdownCounter
        generic
        (
            COUNTER_BITS: natural := 4
        );
        port
        (
            clk: in std_logic; -- clock input
            reset: in std_logic; -- reset input
            up_down: in std_logic; -- up or down input
            enable: in std_logic; -- enable input
            max: in std_logic_vector(COUNTER_BITS - 1 downto 0); -- max value counter
            counter: out std_logic_vector(COUNTER_BITS - 1 downto 0) -- output 4-bit counter
         );
    end component;

    signal reset, clk, enable, up_down: std_logic;
    signal max, counter: std_logic_vector(3 downto 0);

    signal halt_clk: boolean := false;

begin
    DUT: UpdownCounter
        generic map
        (
            COUNTER_BITS => 4
        )
        port map
        (
            clk => clk,
            reset => reset,
            enable => enable,
            up_down => up_down,
            max => max,
            counter => counter
        );

    -- Clock
    ClockProocess :process
    begin
        while not halt_clk loop
            clk <= '0';
            wait for 10 ns;
            clk <= '1';
            wait for 10 ns;
        end loop;
        wait;
    end process;

    StimulusProcess: process
    begin
        max <= "1000"; -- Test value for Counter max value
        enable <= '1';
        reset <= '1';
        up_down <= '0';
        wait for 20 ns;
        reset <= '0';
        wait for 300 ns;
        up_down <= '1';
        --
        wait for 50 ns;
        enable <= '0';
        wait for 50 ns;
        enable <= '1';

        wait for 1000 ns;
        halt_clk <= true;

        wait;
    end process;

end V1;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM