Is there a better way to re-write a BCD_counter in VHDL code with less “if-statement”?

StackOverflow https://stackoverflow.com/questions/9883042

  •  26-05-2021
  •  | 
  •  

Question

I am just beginning to learn VHDL in modelsim, so i apologize in advance if what I'm doing seems really noob.

Basically what i am trying to create is a synthesizable VHDL code for a one-digit up/down BCD counter. The counter will count when "Enable" is '1', or else it stays the same. When input "Init" is initialized, the counter is set to 0 or 9 depending on the value of "Direction" input. (When "Direction" is '1', it is an up counter).

I'm just wondering if there are better tools to use for this to work other than using 100 if and else in a row.

Here is my code, I am writing a test bench for it right now, so I am not yet sure if this will even work. So if you happen to also spot some mistake please point it out for me.

Thanks a lot in advance, and here is my code

entity BCD_counter is
  port(clk, direction, init, enable: in bit;
    q_out: out integer);
end entity BCD_counter;

architecture behaviour of BCD_counter is
  signal q: integer;
begin
  process(clk)
  begin
    if(Clk'event and Clk = '1') then
      if(direction = '1') then -- counting up
        if(init = '1')then --initialize
          q<=0; -- reset to 0
        else
         if(enable = '1')then -- counting          
            if (q<9) then
              q<=q+1;
            else
              q<=0;
            end if;          
         else
          q<=q;
          end if;
        end if;
      elsif(direction = '0') then --counting down
        if(init = '1') then --initialize
          q<=9; --reset to 9
        else
          if(enable = '1') then --counting        
            if (q>0) then
              q<=q-1;
            else
              q<=9;
            end if;       
          else
            q<=q;
          end if;
        end if;
      end if;
    end if;

  end process;  
      q_out <= q;  
end architecture behaviour;
Was it helpful?

Solution

Slightly different style, but this is how I would write it

architecture behaviour of BCD_counter is
  signal next_q : integer;
  signal q      : integer;
begin

  pReg : process
  begin  -- process pReg
    wait until clk'event and clk = '1';
    if init = '1' then
      q <= 0;
    else
      q <= next_q;
    end if;
  end process pReg;

  pCount : process (direction, enable, q)
  begin  -- process pCount
    next_q <= q;

    if enable = '1' then
      if direction = '1' then
        next_q <= q + 1;

        if q = 9 then
          next_q <= 0;
        end if;

      else
        next_q <= q - 1;

        if q = 0 then
          next_q <= 9;
        end if;

      end if;
    end if;
  end process pCount;

  q_out <= q;
end architecture behaviour;

Points to note:

  • The register behaviour is in a separate process from the logic. I find this style is clean. Others have different opinions which normally come down to not liking having next_blah signals.
  • init is your reset signal, so it overrides everything else, and I put reset signals in the register process.
  • The first line of the counter process is what I want to happen by default. In this case it says have the next state of q be the current state.
  • I have the outer if be the check of enable. If we're not enabled we don't do anything, so why check direction first?
  • Inside each half of the direction condition the code structure is the same. Set-up what I want the normal case to be, and then check for the exception to the rule. For example: if we're going up, I set the next state to be q+1, but if q is 9 I override it with q <= 0.
  • I'm not using >, < in any comparisons. These are more expensive than =, and = is just fine.

Alternatively you could take the enable into the register process. It's slightly shorter, and possibly clearer. It also makes it obvious that you're expecting to use the enable pin of a register for this function.

  pReg : process
  begin  -- process pReg
    wait until clk'event and clk = '1';
    if init = '1' then
      q <= 0;
    else
      if enable = '1' then
        q <= next_q;
      end if;
    end if;
  end process pReg;

  pCount : process (direction, q)
  begin  -- process pCount
    if direction = '1' then
      next_q <= q + 1;

      if q = 9 then
        next_q <= 0;
      end if;
    else
      next_q <= q - 1;

      if q = 0 then
        next_q <= 9;
      end if;
    end if;
  end process pCount;

OTHER TIPS

The only thing that comes to my mind is that you could ommit the two

else
   q<=q;

statements because this is implicitly done if none of the other conditions check out.

I do a lot of this - I created a function called modulo_increment which takes an input integer, and "modulus" integer and returns the wrapped around value.

so you can then do

q <= modulo_increment(q, 10);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top