¿Cómo estimar las restricciones de tiempo para los FPGA?

Intento averiguar cómo especificar correctamente las restricciones de tiempo en los diseños de FPGA (en archivos .sdc/ .xdc). Sé lo que significan los tiempos de configuración y espera. Sin embargo: ¿Cómo averiguo qué restricciones de tiempo tiene mi circuito externo?

Lo que espero haber entendido hasta ahora es:

  1. Necesito especificar mis relojes externos (especialmente su velocidad) alimentados en el FPGA mediante el uso de una create_clockdeclaración. Esto asegura que los tiempos internos (entre pines de celdas, por ejemplo, entre FlipFlops o memoria) estén dentro de los límites.

  2. Para todos los pines de entrada, puedo especificar la configuración ( -min) y los tiempos de retención ( -max) para todos los pines de entrada de la FPGA (que se denominan portsen este contexto). Estos son relativos a un reloj y se especifican medianteset_input_delay -clock {clockname} -min/-max <time> [ get_ports {portname} ]

  3. Para todos los pines de salida, puedo especificar -mintiempos de configuración ( ) y retención ( -max) para todos los pines de entrada de la FPGA (que se denominan portsen este contexto). Estos son nuevamente relativos a un reloj y se especifican a través deset_input_delay -clock {clockname} -min/-max <time> [ get_ports {portname} ]

Escenario hipotético

Digamos que la FPGA tiene conectado un reloj externo 'CLK' de 50 MHz. Especificar este es fácil:

create_clock -name CLK -period 20ns [ get_ports {CLK} ]

Ahora se le conecta un microcontrolador (ESP8266, hoja de datos ), que tiene su propio reloj externo de 80 MHz ("CLK").

El microcontrolador envía y recibe sus datos utilizando un sistema de bus sincronizado simple:

  • "TX" => "RX" (µC =>FPGA)
  • "RX" <= "TX" (µC <=FPGA)
  • "reloj" => "reloj" (µC => FPGA, flanco ascendente activado)

Mi microcontrolador tiene el siguiente bucle de programa (pseudocódigo):

BEGIN:
  (TX, CLK) <= (write_data, LOW)  [1th cycle]
  (TX, CLK) <= (write_data, HIGH) [2th cycle]
  (read_data) <= (RX)             [3th cycle]
JUMP BEGIN                        [4th cycle]

Supongamos que el cableado de tx, rx y la línea de reloj tienen una longitud de unos 20 cm y pueden desviarse 5 cm (cable más corto frente a cable más largo). Esto significa un tiempo promedio de 0,67 ns para cada ruta, pero cada señal puede ser +/- 0,17 ns más rápida o más lenta.

Mi enfoque hasta ahora...

Temporización a µC en relación con el flanco ascendente:

(read_data) <= (RX)             -37.5ns <-- last read
JUMP BEGIN                      -25.0ns
(TX, CLK) <= (write_data, LOW)  -12.5ns <-- current data written
(TX, CLK) <= (write_data, HIGH)   0.0ns <-- current low->high
(read_data) <= (RX)              12.5ns <-- current read
JUMP BEGIN                       25.0ns 
(TX, CLK) <= (write_data, LOW)   37.5ns <-- next data written
(TX, CLK) <= (write_data, HIGH)  50.0ns <-- next low->high

Entradas:

Cuando el flanco ascendente del "reloj" llega a la FPGA, los datos en el pin "RX" de la FPGA ya son válidos para 1 ciclo de reloj del µC t=-12.5nsreducido por el máx. Desviación del tiempo de viaje t=-12.33 ns. Por lo tanto, el tiempo de configuración de la FPGA puede ser de hasta 12,33 ns.

Los datos de entrada en "RX" serán válidos para 3 ciclos de reloj del µC reducidos por la incertidumbre del tiempo de viaje: 37,5 ns - 0,17 ns = 37,33 ns.

Salidas:

La salida de datos en el pin "TX" de la FPGA debe ser válida/estable y viajar al pin "RX" de µCs del µC dentro de los 12,5 ns - t_setup del µC. Por lo tanto, debe ser estable en 12.5 ns - 0.67 ns - 0.17 ns - t_setup = 11,66 ns - t_setup. Sin embargo, no sé cómo averiguar t_setup para µC.

Además, el µC no debería enviar datos a earl. Los últimos datos terminan de leerse hasta que t <= -37.5ns + t_holdse miden en µC, lo que significa t <= -38 ns + t_holden el FPGA. Este es el que establece el límite para el tiempo de configuración de la FPGA.

Ahora hay algunos parámetros desconocidos (los µCs setup_time y hold_time). Y no sé si calculo todo bien...

Además, al escribir la restricción, ¿debería usar los valores negados para setup_time en las restricciones o la hora más temprana/última en relación con el evento del reloj?

Aquí está mi solución intermedia/incompleta:

set_input_delay -clock clock -min -12.330ns [ get_ports {RX} ]
set_input_delay -clock clock -max 37.330ns [ get_ports {RX} ]

set_output_delay -clock clock -min -38.000ns [ get_ports {TX} ]
set_output_delay -clock clock -max 12.330ns [ get_ports {TX} ]

Sin embargo, no incluí la configuración y el tiempo de espera del pin "RX" en el µC y de alguna manera necesito especificar la señal de reloj recibida por el µC a través de la línea de "reloj" del bus en el archivo de restricciones, ya que las restricciones se relacionan a este reloj y no al propio reloj externo de 50 MHz de la FPGA. ¿Bien?

Preguntas

  • ¿Cómo especificar correctamente la señal de reloj recibida enviada por el µC?
  • ¿Cómo especificar correctamente los retardos de entrada/salida?
  • ¿Cómo averiguar (o estimar por regla general) el tiempo de configuración/retención de los pines GPIO de µC? (No lo encontré en la hoja de datos; tal vez se llame de manera diferente... ¿qué palabras clave debo buscar? ¿Qué diagramas/nombres de sección?)
  • ¿Cómo interpretar el diagrama del asistente del analizador de tiempo Altera TimeQuest (captura de pantalla a continuación)?

Diagrama en el "TimeQuest Wizzard" en Quartus II

Hay un diagrama de tiempo en el "TimeQuest Wizzard" en Quartus II. Pero no puedo leerlo porque me resultó confuso qué bloque ( <....>) es mi bit de datos actual y qué <////>significa el bloque. Solo pude identificar la señal del reloj, sin saber con seguridad si el estándar está subiendo o bajando. Esto, a su vez, hace que sea difícil concluir cuál de los bloques es cuál y con qué momento se relacionan esas flechas. Tal vez, hay convenciones, pero no las conozco. Así que por favor dame una idea aquí...

Mago de TimeQuest

HOJA DE DATOS DE µC:

En el ejemplo anterior, el µC es un ESP8266 ( hoja de datos ).

EDITAR:

Aquí hay un ejemplo de código fuente de FPGA (VHDL) que, con suerte, explica cómo pienso usar los dos relojes. Por supuesto, la velocidad del reloj asíncrono para los datos debe ser lo suficientemente lenta, de modo que la FPGA tenga suficientes ciclos de reloj para reconocer, que lleguen nuevos datos asíncronos (RX_flag) y para preparar la salida al TX_reg antes del siguiente flanco ascendente en el reloj del µC. Dado el tiempo anterior, el µC tiene 50 ns para reconocer y procesar los datos de entrada. Por lo tanto, debe haber al menos 1 ciclo completo de CLK que tenga medio período de CLK antes (un borde descendente que advierte si los datos ya están disponibles):

   library ieee;
   use ieee.std_logic_1164.all;
   use ieee.std_logic_unsigned.all;
   use ieee.numeric_std.all;

   entity AsyncIO is
     port(
       -- own clock, reset
       CLK : in std_logic;
       reset : in std_logic;

       -- IO-Pins to uC
       clock, RX_pin : in std_logic;
       TX_pin        : out std_logic
     );
   end entity;

   architecture RTL of AsyncIO is

   signal RX_buffer : std_logic := '0'; -- holds received bit
   signal RX_flag   : std_logic := '0'; -- is set when new bit arrive / reset when processed
   signal RX_ready  : std_logic := '0'; -- is set when new bit was available at falling_edge / reset when processed
   signal TX_reg    : std_logic := '0'; -- output that is currently to be send

   signal last_RX : std_logic;
   signal counter : std_logic_vector(1 downto 0) := "00";

   begin
     -- async process
     process (clock) is
     begin
       if rising_edge(clock) then
         RX_buffer <= RX_pin;
         RX_flag <= '1';
         TX_pin <= TX_reg;
       end if;
     end process;

     -- async reset
     process (reset) is
     begin
       if reset = '1' then
         counter <= "00";
                 RX_buffer <= '0';
                 RX_flag <= '0';
                 RX_ready <= '0';
                 TX_reg <= '0';
       end if;
     end process;



     -- synced process
     process (CLK) is

     -- processes RX
     -- count similar bit in a row
     -- TX_reg <= '1' if 5 similar bit in a row
     -- else TX_reg <= '0'
     procedure processRX is
     begin
       if (RX_buffer = last_RX) then
         -- count similar bits
         counter <= counter + 1;
         -- no overflow at value '11'
         -- instead keep at '11' and set TX_reg to '1'
         if counter = "11" then
           counter <= "11";
           TX_reg <= '1';
         end if;
       else
         -- reset if not similar
         counter <= "00";
         TX_reg <= '0';
       end if;   
       -- remind last_RX
       last_RX <= RX_buffer;     
     end;

     begin
       if falling_edge(CLK) then
             if RX_flag = '1' then
                   RX_ready <= '1';
                 end if;
           end if;

       if rising_edge(CLK) then
             -- if RX_read is '1' then RX_flag was already '1' at falling_edge
                 -- hence RX_buffer is safe to read now
             if RX_ready = '1' then
                   processRX; -- call procedure to process bit in RX_buffer
                   RX_flag <= '0';
                   RX_ready <= '0';
                 end if;
           end if;  
     end process;

   end architecture;
Proporcione un enlace a la hoja de datos de su microcontrolador.
Explique cómo se conectan RX, TX y CLOCK al microcontrolador. ¿Son todos parte del mismo registro de E/S de propósito general o TX/RX provienen de un UART? Además, ¿está seguro de que el compilador no reordenará las instrucciones o los accesos de E/S?
Se agregó el enlace a la hoja de datos. Solo imagínelo como SPI con una selección de chip estático. Todos los pines en el mismo banco de puertos µC. Sin reordenar, solo suponga que usaría las instrucciones de ensamblaje. -- NOTA IMPORTANTE: Este es un ejemplo hipotético para mostrar cuál es mi nivel de conocimiento actual y lo que necesito averiguar. Quiero entender cómo calcular las restricciones de tiempo en general.

Respuestas (1)

Como su FPGA y microcontrolador funcionan con diferentes relojes, NO existe una relación de tiempo entre ellos. Para transferir datos de manera segura entre ellos , debe usar sincronizadores o un circuito que tenga una lógica de cruce de dominio de reloj incorporada como un FIFO asíncrono con un reloj de lectura y escritura (Todos los proveedores de FPGA que conozco tienen IP para esos).

Esto también significa que no puede (y por lo tanto no tiene que hacerlo) establecer restricciones de tiempo entre ellos.

Esto es válido tanto para los datos de CLK como de TX de la CPU a la FPGA, y también para los datos de RX de la FPGA al microcontrolador.

Esto todavía lo deja con el problema de cómo configurar el tiempo FPGA para su interfaz de ejemplo con datos CLK y TX. Desafortunadamente, no hay una respuesta simple, ya que depende en gran medida de cómo las instrucciones generan las señales. por ejemplo, ¿el reloj y TX siempre se configuran en el mismo ciclo de reloj? Puede usar el flanco descendente del reloj para registrar los datos.

Por último, pero no menos importante: los sincronizadores y FIFO asíncronos requieren más de un ciclo de reloj para transferir los datos entre dominios de reloj. Por lo tanto, debe tener un CLK en ejecución continua o debe generar varios ciclos más después de haber enviado datos o antes de planear recibir datos.

Buena respuesta, solo quería enfatizar que el OP debe tener sincronizadores para evitar la metaestabilidad.
Gracias por su respuesta: En mi ejemplo, los datos se envían un ciclo de reloj µC (12,5 ns) antes del flanco ascendente del reloj. Por lo tanto, un proceso de FPGA que sea sensible a la señal del reloj debería poder almacenar de forma segura el bit actual en un flip-flop. El FPGA usaría su reloj interno para preparar la salida, que ya está almacenada en un flip-flop cerca del pin de salida. Asumiendo que el FPGA produce un bit (relojes conocidos del µC retrasado) como salida para cada bit de entrada, esto debería funcionar.
¿Qué es un "OP"? @EliotAlderson
OP = Póster original
He agregado un ejemplo de VHDL al final de la pregunta. Esto debería explicar cómo haría mi sincronización.
Ese código es incorrecto. Le sugiero que trate eso en una pregunta separada.