Signal(s) form a combinatorial loop VHDL

fpgavhdl

I was trying to implement Dual-priority encoder but I get following warnings during synthesize:

WARNING:Xst:2170 – Unit prEnc : the following signal(s) form a
combinatorial loop: done, first<3>, req[0]_done_AND_6_o, f.

WARNING:Xst:2170 – Unit prEnc : the following signal(s) form a
combinatorial loop: f.

I got no idea how and where my signals form a combinatorial loop.

Here is the code.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;


entity prEnc is
port( req : in std_logic_vector(7 downto 0);
        first : out std_logic_vector(3 downto 0);
        second : out std_logic_vector(3 downto 0)
);
end prEnc;

architecture Behavioral of prEnc is
signal f, done : std_logic ;
begin
process (req,f,done)
begin
    first <= "0000";
    second <= "0000";
    f <= '0';
    done <= '0';

    if req(7) = '1' then
        first <= "1000";
        f <= '1';
    end if ;
    if req(6) = '1' then
        if f = '0' then
            first <= "0111";
            f <= '1';
        else 
            second <= "0111";
            done <= '1';
        end if;
    end if;
    if req(5) = '1' and done = '0' then
        if f = '0' then
            first <= "0110";
            f <= '1';
        else
            second <= "0110";
            done <= '1';
        end if;
    end if;
    if req(4) = '1' and done = '0' then
        if f = '0' then
            first <= "0101";
            f <= '1';
        else 
            second <= "0101";
            done <= '1';
        end if;
    end if;
    if req(3) = '1' and done = '0' then
        if f = '0' then
            first <= "0100";
            f <= '1';
        else 
            second <= "0100";
            done <= '1';
        end if;
    end if;
    if req(2) = '1' and done = '0' then
        if f = '0' then
            first <= "0011";
            f <= '1';
        else 
            second <= "0011";
            done <= '1';
        end if;
    end if;
    if req(1) = '1' and done = '0' then
        if f = '0' then
            first <= "0010";
            f <= '1';
        else 
            second <= "0010";
            done <= '1';
        end if;
    end if;
    if req(0) = '1' and done = '0' then
        if f = '0' then
            first <= "0001";
            f <= '1';
        else 
            second <= "0001";
            done <= '1';
        end if;
    end if;
end process;

end Behavioral;

Best Answer

You are both setting and reading the signals f and done in the same process; this creates the feedback ("combinatorial loop") that the tools are complaining about.

In order to eliminate that kind of feedback, you need to explicitly list every combination of req:

architecture Behavioral2 of prEnc is
begin
  process (req) begin
    if req(7) = '1' then
      first <= "1000";
      if    req(6) = '1' then second <= "0111";
      elsif req(5) = '1' then second <= "0110";
      elsif req(4) = '1' then second <= "0101";
      elsif req(3) = '1' then second <= "0100";
      elsif req(2) = '1' then second <= "0011";
      elsif req(1) = '1' then second <= "0010";
      elsif req(0) = '1' then second <= "0001";
      else second <= "0000";
      end if;
    elsif req(6) = '1' then
      first <= "0111";
      if    req(5) = '1' then second <= "0110";
      elsif req(4) = '1' then second <= "0101";
      elsif req(3) = '1' then second <= "0100";
      elsif req(2) = '1' then second <= "0011";
      elsif req(1) = '1' then second <= "0010";
      elsif req(0) = '1' then second <= "0001";
      else second <= "0000";
      end if;
    elsif req(5) = '1' then
      first <= "0110";
      if    req(4) = '1' then second <= "0101";
      elsif req(3) = '1' then second <= "0100";
      elsif req(2) = '1' then second <= "0011";
      elsif req(1) = '1' then second <= "0010";
      elsif req(0) = '1' then second <= "0001";
      else second <= "0000";
      end if;
    elsif req(4) = '1' then
      first <= "0101";
      if    req(3) = '1' then second <= "0100";
      elsif req(2) = '1' then second <= "0011";
      elsif req(1) = '1' then second <= "0010";
      elsif req(0) = '1' then second <= "0001";
      else second <= "0000";
      end if;
    elsif req(3) = '1' then
      first <= "0100";
      if    req(2) = '1' then second <= "0011";
      elsif req(1) = '1' then second <= "0010";
      elsif req(0) = '1' then second <= "0001";
      else second <= "0000";
      end if;
    elsif req(2) = '1' then
      first <= "0011";
      if    req(1) = '1' then second <= "0010";
      elsif req(0) = '1' then second <= "0001";
      else second <= "0000";
      end if;
    elsif req(1) = '1' then
      first <= "0010";
      if   req(0) = '1' then second <= "0001";
      else second <= "0000";
      end if;
    elsif req(0) = '1' then
      first <= "0001";
      second <= "0000";
    else
      first <= "0000";
      second <= "0000";
    end if;
  end process;
end Behavioral2;

EDIT

It might be easier to use two single-level priority encoders, using the the first to select the set of inputs that's presented to the second:

architecture Behavioral3 of prEnc is
  signal mask, req_b : stl_logic_vector (7 downto 0);
begin

  process (req) begin
    if    req(7) = '1' then first <= "1000"; mask <= "01111111";
    elsif req(6) = '1' then first <= "0111"; mask <= "00111111";
    elsif req(5) = '1' then first <= "0110"; mask <= "00011111";
    elsif req(4) = '1' then first <= "0101"; mask <= "00001111";
    elsif req(3) = '1' then first <= "0100"; mask <= "00000111";
    elsif req(2) = '1' then first <= "0011"; mask <= "00000011";
    elsif req(1) = '1' then first <= "0010"; mask <= "00000001";
    elsif req(0) = '1' then first <= "0001"; mask <= "00000000";
    else                    first <= "0000"; mask <= "00000000";
    end if;
  end process;

  req_b <= req and mask;

  process (req_b) begin
    if    req_b(7) = '1' then second <= "1000";
    elsif req_b(6) = '1' then second <= "0111";
    elsif req_b(5) = '1' then second <= "0110";
    elsif req_b(4) = '1' then second <= "0101";
    elsif req_b(3) = '1' then second <= "0100";
    elsif req_b(2) = '1' then second <= "0011";
    elsif req_b(1) = '1' then second <= "0010";
    elsif req_b(0) = '1' then second <= "0001";
    else                      second <= "0000";
    end if;
  end process;

end Behavioral3;