Ha diseñado un decodificador asíncrono de n y ha realizado una postimplementación o simulación de temporización.
Debido a que una simulación de tiempo usa el tiempo real de su diseño colocado y enrutado, cada señal tendrá un tiempo fraccionalmente diferente, incluso si las señales son parte del mismo elemento lógico, por ejemplo sw
en su caso.
Cualquiera que sea la lógica que utilice su FPGA para implementar el circuito, porque es asíncrono, si las señales llegan a la entrada de esa lógica en diferentes momentos, la salida pasará a través de estados intermedios en algunos casos cuando su elemento lógico solo realice una transición una vez. Como señala la otra respuesta, estas condiciones de carrera crean pulsos de runt en la salida.
Tomando como ejemplo la transición de sw
de 3
a 4
, las posibles transiciones en las señales binarias que representan este número, dependiendo del enrutamiento detallado de estas señales en el FPGA son:
"011" > "111" > "110" > "100" = 3 > 7 > 6 > 4
"011" > "111" > "101" > "100" = 3 > 7 > 5 > 4
"011" > "010" > "110" > "100" = 3 > 2 > 6 > 5
"011" > "010" > "000" > "100" = 3 > 2 > 0 > 4
"011" > "001" > "000" > "100" = 3 > 1 > 0 > 4
"011" > "001" > "101" > "100" = 3 > 1 > 5 > 4
"011" > "101" > "100" = 3 > 5 > 4
"011" > "110" > "100" = 3 > 6 > 4
"011" > "100" = 3 > 4
Como puede ver, según el enrutamiento y el tiempo resultante, su decodificador podría ver una variedad de entradas durante la transición en sw
, y así producir una variedad correspondiente de salidas. Tenga en cuenta que las transiciones intermedias se producen en un espacio de tiempo muy corto, normalmente en menos de 1 nanosegundo en un FPGA moderno.
Comparemos esto con una de las transiciones que no muestra runts en la salida, cuando sw
va de 4
a 5
. Las posibles transiciones son:
"100" > "101" = 4 > 5
Como solo cambia un bit, solo hay una transición posible. Como resultado, no verá ninguna ejecución en esta transición, sin importar cómo se enruten las señales.
Ahora pensemos en cómo las herramientas realmente implementarán su circuito. Puede verificar el esquema implementado, pero cada salida led
debe ser controlada por un elemento de tabla de consulta (LUT) independiente. Puede usar las herramientas para ver la ecuación lógica de cada LUT, pero esencialmente buscarán ver si la entrada de sw
de 3 bits corresponde a ese led
en particular. Donde la otra respuesta es incorrecta es que solo porque la lógica se implementa en una única LUT, no significa que estas condiciones de carrera sean solo un artefacto de simulación.
Relacionando esto de nuevo con la transición 3
a 4
, debido a que cada salida led
se implementa en una LUT diferente, el tiempo visto por cada LUT será diferente. Vemos pulsos runt en las salidas 1
, 2
, 6
y 7
. De esto podemos deducir que la LUT para led(1)
vio 3 > 1 > 0 > 4 o 3 > 1 > 5 > 4, led(2)
vio 3 > 2 > 6 > 5 o 3 > 2 > 0 > 5, y así sucesivamente.
La forma común de evitar los runts es usar un diseño síncrono, es decir, uno que use un reloj. Tenga en cuenta que para que esto funcione de manera confiable, la entrada ( sw
en este caso) también debe estar sincronizada con clk
.
process(clk)
begin
if (rising_edge(clk)) then
led <= (others => '0');
led(to_integer(unsigned(sw)) <= '1';
end if;
end process;
Ahora, el decodificador n aún verá las diferentes transiciones en las entradas LUT, y tendrá las corridas correspondientes en las salidas LUT, pero estas salidas alimentan un registro. Dado que en un sistema síncrono que ha cumplido con el tiempo, todas las transiciones se habrán completado en el momento en que se produzca el borde del reloj, la salida final no tendrá ningún pulso runt.
Otra opción es decidir que no te interesan estos pulsos runt. En un diseño que simplemente controla algunos LED, es probable que no te importe si existe la posibilidad de que el LED incorrecto se ilumine durante 0,5 nanosegundos.
El punto más importante en todo esto es que estos no son solo artefactos de simulación y podrían causar problemas del mundo real en un diseño.