简体   繁体   中英

Counter 4bit with synchronous load and enable and asynchronous reset.

I have a 4 bit counter made of D flip flops and multiplexers . It counts up to 1111 and then down to 0000. My design is structural. Though i do not know how to make the enable and the load synchronous. Here is my try :

entity counter4Bit is
    Port ( clock : in  STD_LOGIC;
           reset : in  STD_LOGIC;
           load : in  STD_LOGIC;
           enable : in  STD_LOGIC;
           ud : in  STD_LOGIC;
           counterOut : out  STD_LOGIC_VECTOR (3 downto 0));
end counter4Bit;

architecture Behavioral of counter4Bit is

Component MUX
    Port ( sel : in  STD_LOGIC_VECTOR (1 downto 0);
           a : in  STD_LOGIC;
           b : in  STD_LOGIC;
           c : in  STD_LOGIC;
           d : in  STD_LOGIC;
           f : out  STD_LOGIC);
end component;

Component D_FlipFlop
    Port ( D : in  STD_LOGIC;
           Resetn : in  STD_LOGIC;
           Clock : in  STD_LOGIC;
           Q : out  STD_LOGIC);
end component;

signal w: std_logic_vector(3 downto 0);
signal h: std_logic_vector(3 downto 0);
signal q0,q1,q2,q3 :std_logic;
signal nq0,nq1,nq2,nq3 :std_logic;

begin

FF0 : D_FlipFlop
    port map( D => w(0),
                 Resetn => reset,
                 Clock => clock,
                 Q => q0);

FF1 : D_FlipFlop
    port map( D => w(1),
                 Resetn => reset,
                 Clock => clock,
                 Q => q1);

FF2 : D_FlipFlop
    port map( D => w(2),
                 Resetn => reset,
                 Clock => clock,
                 Q => q2);

FF3 : D_FlipFlop
    port map( D => w(3),
                 Resetn => reset,
                 Clock => clock,
                 Q => q3);

MUX0 : MUX
    port map( sel(0) => h(0),
                 sel(1) => load,
                 a => q0,
                 b => nq0,
                 c => '1',
                 d => '1',
                 f => w(0) );

MUX1 : MUX
    port map( sel(0) => h(1),
                 sel(1) => load,
                 a => q1,
                 b => nq1,
                 c => '1',
                 d => '1',
                 f => w(1) );

MUX2 : MUX
    port map( sel(0) => h(2),
                 sel(1) => load,
                 a => q2,
                 b => nq2,
                 c => '0',
                 d => '0',
                 f => w(2) );   

MUX3 : MUX
    port map( sel(0) => h(3),
                 sel(1) => load,
                 a => q3,
                 b => nq3,
                 c => '0',
                 d => '0',
                 f => w(3) );                    

h(0) <= (ud and enable) or (enable and (not ud) );
nq0 <= not q0;

h(1) <= (ud and enable and q0) or (enable and (not ud) and nq0) ;
nq1 <= not q1;

h(2) <= (ud and enable and q0 and q1 ) or (enable and (not ud) and nq1 and nq0);
nq2 <= not q2;

h(3) <= (ud and enable and q0 and q1 and q2 ) or (enable and (not ud) and nq1 and nq2 and nq0);
nq3 <= not q3;

counterOut(0) <= q0;
counterOut(1) <= q1;
counterOut(2) <= q2;
counterOut(3) <= q3;
end Behavioral;

Is this some academic homework or something like that? If not, throw away all those flipflop instances and muxes and just write one clocked procedure. Something along the line of:

signal count : integer range 0 to 15;

process(clk, rst)
  begin
    if rst = '0' then
      count <= 0;    
    elsif rising_edge(clk) then
      if enable = '1' then
        if load = '1' then
          count <= <somevalue>;
        elsif count < 15 then
          count <= count + 1;
        else
          count <= 0;
        end if;^
      else
        count <= 0;
    end if;
end process;

Because you didn't include the entity/architecture pairs for for D_FlipFlop or MUX I figured I'd demonstrate with a process substituting for all 4 FFs and concurrent conditional signal assignment statements substituting for the multiplexers.

The idea here is to demonstrate how to use bit-wide four input multiplexers although there are some things we can describe based on the counter value as a whole.

Enabled and counting up presents the FF inputs a value equal to the counterout + 1, something we refer to as an increment, and that only takes one xor for each element of the counter and the carry tree.

Likewise counting down presents a decrement input.

It turns out the LSB always toggles when enabled so the LSB of the counter can have a not counter LSB input.

(As chip designers we used to remember this stuff in an earlier era. You paid for a license to use arithmetic elements (eg "+" or "-" operators). A sort of "You have '0's? Way back when we used to lie '1's on their side" sort of recollection. In any event you tend to remember the short cuts, increment and decrement with '0' values for the B input of an adder drops the one XOR and requires the not values.)

The four inputs to the multiplexers require two select inputs. You can arbitrarily assign function to inputs and select values. For example:

 hold (no enable, no load) 00 load 01 enable and up 10 enable and down 11 

The select lines for that would be:

sel(1) <= enable and not load;  -- overriding load
sel(0) <= load or (not load and enable and ud);

Where load takes precedence over counting. The sel inputs are used to all four multiplexer. Note that equations for "10" and "11" values of sel are combined on the following code's MUX0, you can use a 4 input multiplexer and supply not q(0) to both inputs:

library ieee;
use ieee.std_logic_1164.all;

entity counter4bit is  -- updown counter sync load, enable, async reset
    port ( 
        clock:       in  std_logic;
        reset:       in  std_logic;
        load:        in  std_logic;
        enable:      in  std_logic;
        ud:          in  std_logic;  -- assume up  = '0', down = '1'
        counterin:   in  std_logic_vector (3 downto 0); -- ADDED
        counterout:  out std_logic_vector (3 downto 0)
    );
end entity counter4bit;

architecture foo of counter4bit is
    signal sel:     std_logic_vector (1 downto 0); -- mux selects
    signal din:     std_logic_vector (3 downto 0); -- outputs of muxes to FFs
    signal q:       std_logic_vector (3 downto 0); -- output of FFs
    signal incr:    std_logic_vector (3 downto 1);
    signal decr:    std_logic_vector (3 downto 1);
begin

FLIPFLOPS:  -- abstract the structural FFs away, no MCVE provided.
    process (reset, clock)
    begin
        if reset = '0' then  -- resetn on FF component declaraiton 
            q <= (others => '0');  -- reset all FFs to '0'
        elsif rising_edge(clock) then
            q <= din;
        end if;
    end process;

    -- Pick values of select for the conditions 
    -- hold (no enable, no load) 00
    -- load                      01
    -- enable and up             10
    -- enable and down           11

    sel(1) <= enable and not load;  -- overriding load
    sel(0) <= load or (not load and enable and ud);

    -- UP incrementer

--  incr(0) <= not q(0);
    incr(1) <= q(1) xor q(0);
    incr(2) <= q(2) xor (q(0) and q(1));
    incr(3) <= q(3) xor (q(0) and q(1) and q(2));

    -- DOWN decrementer

-- decr(0) <= not q(0);
    decr(1) <= q(1) xor not q(0);
    decr(2) <= q(2) xor (not q(0) and not q(1));
    decr(3) <= q(3) xor (not q(0) and not q(1) and not q(2));

-- no MCVE provided multiplexers either

MUX0:
    din(0) <= (q(0)         and not sel(1) and not sel(0)) or  -- hold "00"
              (counterin(0) and not sel(1) and     sel(0)) or  -- load "01"
           -- (incr(0)      and     sel(1) and not sel(0)) or  -- up   "10"
           -- (decr(0)      and     sel(1) and     sel(0));    -- down "11"
              (not q(0)     and     sel(1));                   -- "10" | "11"

              --  din(0) only requires a 3 input mux

MUX1:
    din(1) <= (q(1)         and not sel(1) and not sel(0)) or  -- hold "00"
              (counterin(1) and not sel(1) and     sel(0)) or  -- load "01"
              (incr(1)      and     sel(1) and not sel(0)) or  -- up   "10"
              (decr(1)      and     sel(1) and     sel(0));    -- down "11"

            -- din(1) through din(3) require 4 input muxes

MUX2:
    din(2) <= (q(2)         and not sel(1) and not sel(0)) or  -- hold "00"
              (counterin(2) and not sel(1) and     sel(0)) or  -- load "01"
              (incr(2)      and     sel(1) and not sel(0)) or  -- up   "10"
              (decr(2)      and     sel(1) and     sel(0));    -- down "11"

MUX3:
    din(3) <= (q(3)         and not sel(1) and not sel(0)) or  -- hold "00"
              (counterin(3) and not sel(1) and     sel(0)) or  -- load "01"
              (incr(3)      and     sel(1) and not sel(0)) or  -- up   "10"
              (decr(3)      and     sel(1) and     sel(0));    -- down "11"           
OUTPUT:
    counterout <= q; 

end architecture;

The other thing of note is that there's an added input port to supply the load value, arbitrarily named counterin to match counterout.

So a quick and dirty testbench to exercise the abstracted model:

library ieee;
use ieee.std_logic_1164.all;

entity counter4bit_tb is
end entity;

architecture foo of counter4bit_tb is
    signal clock:       std_logic := '0';
    signal reset:       std_logic;  -- '0' for reset
    signal load:        std_logic;
    signal enable:      std_logic;
    signal ud:          std_logic; -- up  = '0', down = '1'
    signal counterin:   std_logic_vector (3 downto 0);
    signal counterout:  std_logic_vector (3 downto 0);
begin
DUT:
    entity work.counter4bit
        port map (
            clock => clock,
            reset => reset,
            load  => load,
            enable => enable,
            ud => ud,
            counterin => counterin,
            counterout => counterout
        );
CLKGEN:
    process
    begin
        wait for 5 ns;
        clock <= not clock;
        if now > 380 ns then
            wait;
        end if;
    end process;

STIMULIS:
    process
    begin
        wait for 6 ns;
        reset <= '0';
        load <= '0';
        enable <= '0';
        ud <= '0';  -- up
        counterin <= (others => '1');
        wait for 20 ns;
        reset <= '1';
        load <= '1';
        wait for 10 ns;
        load <= '0';
        wait for 10 ns;
        enable <= '1';  
        wait for 160 ns;
        ud <= '1';  -- down
        wait for 160 ns;
        enable <= '0';
        wait;
    end process;
end architecture;

And that gives us:

counter4bit_tb.png

Which shows the increment and decrement are correct, as well as the multiplexer inputs.

So here's one way to organize the four input muxes to provide hold (no increment, no decrement, no load), load, increment and decrement. You could also note it anticipates an asynchronous reset.

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