Señal (es) forman un lazo combinatorio VHDL

0

Estaba tratando de implementar el codificador de prioridad dual pero recibo las siguientes advertencias durante la síntesis:

ADVERTENCIA: Xst: 2170 - unidad prEnc: las siguientes señales forman un bucle combinatorio: hecho, primero < 3 & gt ;, req [0] _done_AND_6_o, f.

ADVERTENCIA: Xst: 2170 - Unidad prEnc: las siguientes señales forman un bucle combinatorio: f.

No tengo idea de cómo y dónde mis señales forman un bucle combinatorio.

Aquí está el código.

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;
    
pregunta Al Bundy

2 respuestas

3

Estás configurando y leyendo las señales f y done en el mismo proceso; esto crea la retroalimentación ("bucle combinatorio") de la que se quejan las herramientas.

Para eliminar ese tipo de comentarios, debes enumerar explícitamente cada combinación de 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;

EDITAR

Puede ser más fácil usar dos codificadores de prioridad de un solo nivel, usando el primero para seleccionar el conjunto de entradas que se presenta al segundo:

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;
    
respondido por el Dave Tweed
1

Cuando se requieren operaciones repetitivas como esta, a menudo la respuesta es un bucle For (dentro de un proceso).

La gente se aleja de los bucles, y no estoy seguro de por qué: posiblemente algunas herramientas de síntesis antiguas tuvieron problemas con ellos, pero ahora hacen un buen trabajo al sintetizar los bucles, funciones, procedimientos, etc. Con vistas a la generación de hardware. (NB: lo siguiente solo se aplica a los procesos SIN RECIBIR instrucciones, por simplicidad)

Y eso significa tener en cuenta cómo la herramienta de síntesis "ejecuta" el bucle ...

Ejemplo: (advertencia: ¡no probado en simulación!)

use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.all;

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

architecture Loopy of prEnc is
begin

  process (req) begin
    first <= "0000";    -- default assignments
    second <= "0000";
    outer:
    for i in req'range loop  -- req range is 7 downto 0
      if req(i) = '1' then
         first <= to_unsigned(i+1,first'length);
         inner:
         for j in req'range loop
            if j < i and req(j) = '1' then
               second <= to_unsigned(j+1, second'length);
               exit inner;
            end if;
         end loop;
         exit outer;
       end if;
    end loop;
  end process;

end Loopy;

Puede verlo como ejecutado de manera secuencial, paso a paso, PERO en un breve instante llamado "ciclo delta". Y si no estás familiarizado con estos, aprendelos. Esta Q & A puede ayudar. Lo que sucede es que la herramienta de síntesis desenrolla el bucle, por lo que cada iteración se ejecuta en paralelo, pero el efecto será el mismo que si cada paso se ejecutara a su vez.

Las variables (como las variables de bucle I, J) actualizan sus valores inmediatamente, pero las señales no se actualizan hasta el final del proceso. Por lo tanto, la última asignación para señalar "primero" gana. La asignación predeterminada en la parte superior del proceso se aplica SOLAMENTE si no ocurren otras asignaciones.

Un par de reglas simples:
1) Hacer que los límites del bucle sean estáticos. En el bucle interno, en lugar de 'para j = i downto 0', itere j en todo el bucle, comparando con i para ver si necesitamos ejecutar la prueba. Esto sintetizará bastante hasta el mask en la segunda versión de David.

2) Tenga en cuenta que, si no es cuidadoso, desenrollar el bucle puede generar una pieza ENORME de hardware, y que el análisis de tiempo informará que la ejecución "instantánea" demora mucho más que su período de reloj. Así que ten cuidado. (Pero verá estos defectos en el informe de síntesis y eso le dirá si necesita mejorar)

Y un punto de estilo: prefiero usar el sistema de tipos en lugar de combatirlo. Como first,second son números sin firmar, los hice unsigned . Más claro, y guarda las conversiones de tipos ...

¿Qué tan grande es esta cosa con dos bucles anidados en comparación con los originales? Xilinx XST 14.4 da los siguientes resultados (para Artix-7)

  

conductual2:   Utilización de Slice Logic:
      Número de LUT de corte: 10 de 63400 0%
      Número utilizado como lógica: 10 de 63400 0%

     

behavioral3: Slice Logic Utilization:
      Número de LUT de corte: 11 de 63400 0%
      Número utilizado como lógica: 11 de 63400 0%

     

loopy: Slice Logic Utilization:
      Número de LUT de corte: 10 de 63400 0%
      Número utilizado como lógica: 10 de 63400 0%

Entonces ... debido a que los límites del bucle son todos estáticos (constantes locales), las estructuras y las adiciones del bucle se optimizan para nada. Lo que queda es el mismo tamaño que el original.

(EDIT: como Dave señala que debería haber simulado, olvidé abortar el bucle en el primer éxito ... la versión revisada sintetiza a 11 LUTs. Ya sea más fácil acertar el bucle simple o el gran corte original 'n'paste está en debate. Creo que mi punto de que hay un enfoque "bueno" ... ¡pero no "a prueba de errores"! ... el uso de bucles sigue en pie)

    
respondido por el Brian Drummond

Lea otras preguntas en las etiquetas