optimización de síntesis vhdl: contadores en estadísticas

2

Tengo una pregunta general sobre la eficiencia de una máquina de estado sintetizable.

La primera versión usa el mismo contador para cada estado. El segundo usa un contador propio para cada estado. ¿Qué versión de las dos es más eficiente (área lógica, velocidad ...)?

¿Cuánta área del FPGA está ocupada por el enrutamiento de la señal count1 cuando uso el mismo contador para cada estado? ¿Es mejor usar un contador para cada estado?

Espero que alguien con más experiencia pueda explicar qué solución es la mejor (quizás una tercera versión) y por qué.

¡Gracias!

Saludos cordiales,

Oliver

- 1. Versión ========================================== =====================

signal count1: integer range 0 to 1000 := 1000;  
type mystates is (s1, s2, s3, s4);  
signal mymode: mystates := s1;  

BEGIN  

MyProcess: process(clk)  

BEGIN  

    IF (clk'event and clk = '1') THEN  

        case mymode is  
        when s1 =>   
            If (count1 = 0) then  
            mymode <= s2;
            count1 <= 555;
            -- (stuff)
            else  
            count1 <= count1 - 1;  
            end if;  
        when s2 => 
            If (count1 = 0) then  
            mymode <= s3;
            count1 <= 666;
            -- (stuff)
            else  
            count1 <= count1 - 1;  
            end if; 
        when s3 => 
            If (count1 = 0) then  
            mymode <= s4;
            count1 <= 784;
            -- (stuff)
            else  
            count1 <= count1 - 1;  
            end if; 
        when s4 =>  
            If (count1 = 0) then  
            mymode <= s1;
            count1 <= 1000;
            -- (stuff)
            else  
            count1 <= count1 - 1;  
            end if; 
        when others =>  
            Null;  
        end case;  

    END IF;

end process;

- 2. Versión ========================================== =====================

signal count1, count2, count3, count4: integer range 0 to 1000 := 1000;  
type mystates is (s1, s2, s3, s4);  
signal mymode: mystates := s1;  

BEGIN  

MyProcess: process(clk)  

BEGIN  

    IF (clk'event and clk = '1') THEN  

        case mymode is  
        when s1 =>   
            If (count1 = 0) then  
            mymode <= s2;
            count1 <= 555;
            -- (stuff)
            else  
            count1 <= count1 - 1;  
            end if;  
        when s2 => 
            If (count2 = 0) then  
            mymode <= s3;
            count2 <= 666;
            -- (stuff)
            else  
            count2 <= count2 - 1;  
            end if; 
        when s3 => 
            If (count3 = 0) then  
            mymode <= s4;
            count3 <= 784;
            -- (stuff)
            else  
            count3 <= count3 - 1;  
            end if; 
        when s4 =>  
            If (count4 = 0) then  
            mymode <= s1;
            count4 <= 1000;
            -- (stuff)
            else  
            count4 <= count4 - 1;  
            end if; 
        when others =>  
            Null;  
        end case;  

    END IF;

end process;
    
pregunta Olli

2 respuestas

7

La primera versión será más eficiente en términos de área y velocidad, pero ninguna es muy buena, en mi humilde opinión.

Una forma muy rápida de estimar el tamaño / velocidad de algo es pensar en cada señal de salida y de cuántas entradas se derivan de la salida. Por ejemplo: a < = b xor c. Decimos que 'a' es una función de 2 señales (byc). Cuantas más "entradas" haya, más lógica se requerirá y más lento se ejecutará. Tenga en cuenta que esta es una estimación súper aproximada, pero es útil para hacer estimaciones súper aproximadas.

En la versión 1, tiene su "salida" de mymode, que es una función de muchas entradas. La entrada importante es count1, que es una señal de 10 bits. Entonces, sin considerar las otras señales, puede decir que mymode es al menos una función de 10 entradas. Por otro lado, la versión 2 tiene 4 entradas de conteo (cada una de 10 bits), por lo que es una función de al menos 40 entradas. Eso es un montón de entradas, y creará mucha lógica que se ejecuta lentamente.

Ahora, aquí hay una manera súper fácil de hacer que la lógica para ambas versiones sea más pequeña y más rápida. Para este ejemplo, solo voy a hacer un contador simple que "hace algo" cuando termina, cuenta. Puedes adaptar las mismas técnicas a tu máquina de estados. Primero, aquí está tu versión:

signal count :integer range 0 to 1000;  

process (clk)
begin
  if rising_edge(clk) then
    if load='1' then
      count <= some_constant_value;
    elsif count=0 then  -- This line is important
      do something here;
    else
      count <= count - 1;
    end if;
  end if;
end process;

Y aquí está mi versión:

signal count :std_logic_vector (10 downto 0);  -- Note:  1 extra bit

process (clk)
begin
  if rising_edge(clk) then
    if load='1' then
      count <= some_constant_value - 1;
    elsif count(count'high)='1' then  -- This line is important
      do_something_here;
    else
      count <= count - 1;
    end if;
  end if;
end process;

Tu versión cuenta desde N hasta 0, mientras que la mía cuenta desde N-1 hasta -1. Para hacer que esto funcione, hice que la señal de conteo fuera un poco más grande y también una SLV en lugar de un entero. Pero donde esto realmente hace que las cosas sean más rápidas es que su versión está haciendo una comparación de N bits donde la mía es solo revisar un solo bit. En esencia, estoy usando la lógica de la cadena de transporte de la línea "count < = count - 1" para hacer mi comparación. La lógica de la cadena de transporte ya está ahí para el contador, solo lo estoy haciendo un poco más largo. Dado que la lógica de la cadena de transmisión es súper rápida en un FPGA, y ya la estás usando, la lógica resultante es muy pequeña y súper rápida.

Para nuestro contador de 10 bits, la línea "elsif count = 0 then" requeriría tres LUT de 4 entradas y 2 niveles de lógica en un Xilinx Spartan-3. Mi versión requiere 1 Flip-Flop (y una cadena de transporte asociada que de otra forma no se habría usado) y esencialmente 0 niveles de lógica.

Pero digamos que el contador era de 32 bits. Su versión requeriría 11 LUTs y 3 niveles de lógica. El mío se mantendría igual en 1 FF y 0 niveles.

Cuando aplique mi método a las dos versiones de su máquina de estado, cada versión funcionará. La versión 1 sigue siendo el mejor enfoque, pero en algunas circunstancias no puede tener un solo contador, por lo que debe usar la versión 2. Con mi método, en lugar de tener una función de al menos 40 entradas, tiene una función de al menos 4 entradas. 4 es mucho mejor que 40!

    
respondido por el user3624
3

Primero que todo, usted no necesita la cláusula de "otros" en este caso, ya que ha cubierto todos los casos posibles (desde el punto de vista del idioma).

A continuación, ha eliminado tanto de su código que ninguna de las máquinas de estados realizará ningún trabajo real. Pero si tuviera que adivinar, las dos versiones que escribes tendrían un comportamiento diferente: una tiene un contador para cada estado y la otra tiene un contador global. Uno usará más lógica y más registros que el otro.

Si no necesita almacenar los resultados del contador intermedio, le sugiero que solo use un registro de conteo.

Finalmente, si realmente quiere saber, intente con ambos y observe los resultados de la síntesis . Esa información es mucho más confiable que cualquier otra cosa que podamos escribir en este foro.

    
respondido por el Philippe

Lea otras preguntas en las etiquetas