Search code examples
delayvhdl

VHDL code help- output once cycle earlier


In the following code i get output one cycle earlier. I am expecting a register to be formed for both pos_cnt and neg_cnt. The synthesis tool gives 2 counters with no registers. Why?

architecture rtl of divide_by_3 is
  signal pos_cnt :std_logic_vector (1 downto 0):="00";
  signal neg_cnt :std_logic_vector (1 downto 0):="00";
begin
  process (clk, reset) begin
      if (reset = '1') then
          pos_cnt <= (others=>'0');
      elsif (rising_edge(clk)) then
          if (pos_cnt /= "01") then
              pos_cnt <= pos_cnt + 1;              
 else
    pos_cnt <= (others=>'0');
    end if;
      end if;
  end process;

  process (clk, reset) begin
      if (reset = '1') then
          neg_cnt <= (others=>'0');
      elsif (falling_edge(clk)) then
          if (neg_cnt /="01") then
             neg_cnt <= neg_cnt + 1; 
          else
    neg_cnt <= (others=>'0');
    end if;
      end if;
  end process;

  cout <= '1' when ((pos_cnt="01") and (neg_cnt ="01")) else
          '0';

end architecture;


Solution

  • Distinguishing between a register and a counter is a bit misleading. The only difference between your code and code that generates a standard register or flip-flop is that the input to your counter comes from the counter itself. If I take the liberty of removing the special wraparound case from your code, one of your counters becomes:

    Count1 : process (clk, rst)
    begin
      if rst = '1' then
        pos_cnt <= (others => '0');
      elsif rising_edge(clk) then
        pos_cnt <= pos_cnt + 1;
      end if;
    end process Count1;
    

    A basic register is:

    Reg1 : process (clk, rst)
    begin
      if rst = '1' then
        q <= (others => '0');
      elsif rising_edge(clk) then
        q <= d;
      end if;
    end process Reg1;
    

    q lags d by one clock cycle. Now, you could rewrite Count1 as:

    signal next_pos_cnt : ...
    
    ...
    
    next_pos_cnt <= pos_cnt + 1;
    
    Count2 : process (clk, rst)
    begin
      if rst = '1' then
        pos_cnt <= (others => '0');
      elsif rising_edge(clk) then
        pos_cnt <= next_pos_cnt;
      end if;
    end process Count2;
    

    The function is identical to Count1, and you should recognize that the clocked process is virtually identical to Reg1. Both are registers. One just takes an external input, and the other has feedback.

    So when you say that you expect the counter to behave like the register, you may just be missing the fact that the counter input is just a (combinational) function of itself. The counter's next value (assigned on the clock edge) lags behind its input by one clock cycle, just like the register. The only difference is where the input comes from. So, since its starting value is 0, on the first clock edge after reset, it becomes itself (0) + 1. Make sense? Where would the extra clock cycle delay be?

    If there are any parts of this that you don't understand or that don't answer your question, please let me know.

    edit: I meant to mention that you could add a clock enable for the counter if you wanted, like so:

    ...
    elsif rising_edge(clk) then
      if clk_en = '1' then
        pos_cnt <= pos_cnt + 1;
      end if;
    end if;
    

    Then, the value of pos_cnt would change one clock after you asserted clk_en. Maybe that would be closer to the result you were expecting.