Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
8 years ago

Combinational Loop In VHDL synthesis

Dear all

I've been working on a project in which I build an interconnection network with similar modules. Each module has 4 inout dataports. Also they have two control ports, one for R/W (Read or Write) and one for switching (like a crossbar switch). To build up the network I need to connect these modules together via their inout data ports. I want to be able to transfer data bidirectionally. I have included my code at the end. This code just has two modules connected to each other.

- After synthesis in Quartus, ISE, or Synopsys Design Compiler or Synplify Pro, I get warnings which says there are a lot of nodes with combinational loop. But Why? Have I done anything wrong?

- The .vho netlist I get from Quartus, has inout ports with std_logic_vector type while my original design signed inout ports. Is this resulting from the combinational loops the synthesizer detects?

I would be grateful if anyone can help me with this.

The Module

    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    entity Inter_Con_Mod is
        generic(WL: integer:= 8);
        port(PortL0,PortL1,PortR0,PortR1: inout signed(WL-1 downto 0);
              RW: in std_logic;
                SW: in std_logic);
               
    end Inter_Con_Mod;
    
    architecture Behav of Inter_Con_Mod is
    
    begin
     
     PortR0 <= PortL0 when (SW = '0' and RW = '0') else
                  PortL1 when (SW = '1' and RW = '0') else
                (others => 'Z');
     PortR1 <= PortL1 when (SW = '0' and RW = '0') else
                  PortL0 when (SW = '1' and RW = '0') else
                (others => 'Z');
    
     PortL0 <= PortR0 when (SW = '0' and RW = '1') else
                  PortR1 when (SW = '1' and RW = '1') else
                (others => 'Z');
     PortL1 <= PortR1 when (SW = '0' and RW = '1') else
                  PortR0 when (SW = '1' and RW = '1') else
                (others => 'Z');
    

The Interconnection Example (Top Module)

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity Datapath is
    generic(WL: integer:=8);
    port(DL0,DL1: inout signed(WL-1 downto 0);
          DR0,DR1: inout signed(WL-1 downto 0);
          C0,C1: in std_logic;
          RW: in std_logic);
          
end Datapath;
architecture Behavioral of Datapath is
       component Inter_Con_Mod is
            generic(WL: integer);
            port(PortL0,PortL1,PortR0,PortR1: inout signed(WL-1 downto 0);
                    RW: in std_logic;
                    SW: in std_logic);
         end component;
         signal M0_L0,M0_L1,M0_R0,M0_R1: signed(WL-1 downto 0);
         signal M1_L0,M1_L1,M1_R0,M1_R1: signed(WL-1 downto 0);
         
begin
     
     M0: Inter_Con_Mod 
            generic map(WL => WL)
            port map (M0_L0,M0_L1,M0_R0,M0_R1,RW,C0);
     M1: Inter_Con_Mod 
            generic map(WL => WL)
            port map (M1_L0,M1_L1,M1_R0,M1_R1,RW,C1);
    
     DL0 <= M0_L0 when RW = '1' else
              (others => 'Z');
     DL1 <= M0_L1 when RW = '1' else
              (others => 'Z');
    
     M0_L0 <= DL0 when RW = '0' else
                 (others => 'Z');
     M0_L1 <= DL1 when RW = '0' else
                 (others => 'Z');
     M1_L0 <= M0_R0 when RW = '0' else
                 (others => 'Z');
     M1_L1 <= M0_R1 when RW = '0' else
                 (others => 'Z');
                  
                 
     M0_R0 <= M1_L0 when RW = '1' else
                 (others => 'Z');
     M0_R1 <= M1_L1 when RW = '1' else
                 (others => 'Z');
     M1_R0 <= DR0 when RW = '1' else
                 (others => 'Z');
     M1_R1 <= DR1 when RW = '1' else
                 (others => 'Z');
     
     DR0 <= M1_R0 when RW = '0' else
                 (others => 'Z');
    DR1 <= M1_R1 when RW = '0' else
                 (others => 'Z');                 
                               
                              
end Behavioral;

15 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    The combinational loops are pretty clear. In your first assignment, PortL0 drives PortR0 and then in your third PortR0 drives PortL0. You of course intend the when clauses to make them mutually exclusive, but I doubt if the tools are that smart. You should use the proper VHDL constructs for mutually exclusive cases:

    
    if(SW='0' and RW='0') then
      PortR0 <= ...
      PortR1 <= ...
      PortL0 <= ...
      PortL1 <= ...
    elsif(SW='0' and RW='1') then
      ...
    elsif(SW='1' and RW='0') then
     ...
    else
     ...
    end if;
    

    Or a case statement:

    	
    	test_proc : process(RW, SW, PortR0, PortL0)
    		variable sel : std_logic_vector(1 downto 0);
    	begin
    	
    		sel := SW & RW;
    	
    		case sel is
    		when "00" =>
    			PortR0 <= PortL0;
    			PortL0 <= 'Z';
    		when "01" =>
    			PortL0 <= PortR0;
    			PortR0 <= 'Z';
    		when others =>
    			PortR0 <= 'Z';
    			PortL0 <= 'Z';
    		end case;
    	
    	end process;
    

    You could still run into trouble though with multiple drivers at a higher level.

    It's not entirely clear what you are trying to do, but inout's are best avoided.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Yeah. I had also seen this kind of implementation but I didn't know there were a preference for this. Thanks anyway. I will test it.

    As I mentioned in my former posts, I want to build a bidirectional interconnection network between some processors and some memories. This is just sample of my interconnection and I wanted to solve the combinational loop issue.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Project does have an ELF file. Please make sure project has been buil succcessfully

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    Yeah. I had also seen this kind of implementation but I didn't know there were a preference for this. Thanks anyway. I will test it.

    As I mentioned in my former posts, I want to build a bidirectional interconnection network between some processors and some memories. This is just sample of my interconnection and I wanted to solve the combinational loop issue.

    --- Quote End ---

    Point taken. Buses between chips is one of the few cases where bidirectional lines may make sense since it saves board traces. Of course, you lose the possibility of sending and receiving at the same time and will have all sort of coordination issues unless you have one master.

    I think the case statements (or if/else) actually make the code much more clear since it makes it obvious what the outputs are for a given set of inputs (SW and RW in your case).
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    Dear all

    I've been working on a project in which I build an interconnection network with similar modules. Each module has 4 inout dataports. Also they have two control ports, one for R/W (Read or Write) and one for switching (like a crossbar switch). To build up the network I need to connect these modules together via their inout data ports. I want to be able to transfer data bidirectionally. I have included my code at the end. This code just has two modules connected to each other.

    - After synthesis in Quartus, ISE, or Synopsys Design Compiler or Synplify Pro, I get warnings which says there are a lot of nodes with combinational loop. But Why? Have I done anything wrong?

    --- Quote End ---

    Your entire design is asynchronous because there is no clock.

    You use tristates in internal logic (not connected to I/O pins), and the fabric does not have internal tristates, so the synthesis tool attempts to implement your logic using multiplexers.

    When it does that, because your design is asynchronous, combinatorial loops are created. If you look at the netlist output from the synthesis tool, you might see that.

    The solution is to code this properly: don't use internal tristates, use proper muxes, and make sure you don't have logic loops.