Este código tiene algunos pequeños problemas sintácticos, pero en general no está lejos y será una forma útil de distinguir entre sintetizable y no sintetizable, ¡lo que realmente no es lo que estás esperando!
1) El mapa del puerto
port(therm : inout std_logic_vector(6 downto 0); -- thermometer code
bin : out std_logic_vector(2 downto 0); -- binary code
i : integer range 0 to 7);
Puntos a tener en cuenta aquí:
-
therm
y bin
tienen un modo y un tipo; i
solo tiene un tipo. Como bin
es solo una copia de i
, realmente no necesita ambos en la lista de puertos. Puede declarar i
internamente como una señal, o incluso en el proceso como una variable.
-
bin
representa un número sin firmar. Tan buen estilo es hacerlo sin firma; o incluso Integer, y transmitir más de la intención del diseño al lector. Ambos son perfectamente sintetizables. El entero puede darle un entero de 32 bits, así que hágalo bin : out natural range 0 to 7;
y obtendrá un entero sin signo de 3 bits. La lección aquí es que si está realizando muchas conversiones de tipos innecesarias, DETÉNGASE: piense, y encontrará una manera de utilizar el sistema de tipos en lugar de luchar .
-
therm
ha sido declarado " inout
" pero en realidad es una entrada al proceso. (El hecho de que lo estés modificando internamente es un detalle de la implementación, ¡REALMENTE no quieres exponer la versión modificada al mundo exterior!) De hecho, " inout
" realmente no hace lo que crees que hace. Su propósito real es solo para buses de datos y similares, donde se comunica en ambos sentidos con la misma señal. Si lo usa como está, entonces cualquier valor que genere el valor original en therm
seguirá manejando therm
, y sus valores modificados entrarán en conflicto con eso para producir " X
", es decir, un valor desconocido (o en hardware real, posiblemente recalentar y quemar!).
Así que elimine i
, cree bin
sin firmar o un subtipo de Natural, y haga de therm
una entrada.
2) Necesitas una copia local de therm
que puedas modificar. Declararlo localmente como una señal.
architecture behavioral_g of therm2bin_g is
therm_int : std_logic_vector(6 downto 0);
begin
Y i
también debe declararse localmente. También podría ser una señal, pero seamos una variable en el proceso.
golden : process(therm)
variable i : integer := 0;
-- yes, it is important to initialise it!
begin
3) El bucle.
Primero debemos copiar la entrada en la señal interna, luego podemos modificarla en el bucle.
therm_int <= therm;
while (therm_int /= "00000000") loop
therm_int <= therm_int srl 1;
i := i + 1;
end loop;
Para simplificarlo, podrías hacer que therm_int no esté firmado y escribir while therm_int /= 0 loop
(perdiendo los paréntesis del estilo C en el proceso)
Hay otro problema aquí. Piense en un proceso como en un pequeño programa en C (pero sin algunas de las "características" más estupendas de C) - las variables funcionan más bien como espera - BUT - las señales están diseñadas esencialmente para la comunicación entre procesos en un sistema de procesamiento paralelo. Si piensas en términos de C, ¡el equivalente más cercano es una tubería que se abre en la salida estándar y se enrolla nuevamente en la entrada estándar! Puedes escribir en una tubería pero no pasa nada hasta que lo desatas ...
En VHDL, la descarga solo se producirá cuando el proceso se suspenda. Como está escrito, no puede suspenderse hasta que el bucle finalice y llegue a " end process
". Y no puede terminar el bucle hasta " therm_int = 0
". Y no puede cambiar el valor visto en therm_int
hasta que se suspenda ... esto es un bucle infinito.
Para comprender por qué las señales VHDL funcionan de esta manera, consulte esta Q & A
La forma más sencilla de evitar esto es hacer que therm_int
sea otra variable de proceso y usar la asignación de variable :=
en lugar de la asignación de señal <=
para ella.
Y ahora debería funcionar.
4) Síntesis.
¿Pero qué no es sintetizable al respecto?
Solo esto: ¡usaste while
loop en lugar de for
loop!
Piense en eso por un momento: generalmente no puede predecir cuántos ciclos tomará un ciclo while
. Para la síntesis, eso significa que tienes que generar una cantidad desconocida de hardware!
Pero podría colocar un límite superior en las iteraciones y generar hardware para atender ese límite superior. De hecho, un bucle for
se delimita automáticamente, y las herramientas de síntesis pueden manejarlo.
Así que escribe el bucle como
therm_int := therm;
for j in therm_int'range loop
if therm_int /= 0 then
therm_int := therm_int srl 1;
i := i + 1;
end if;
end loop;
y sintetízalo.
Notas: for j in therm_int'range loop
; porque j? ¡Bueno, no queremos ocultar tu variable i
!
Y tenga en cuenta que therm_int'range
equivale automáticamente a (6 downto 0)
o, sin embargo, declaró therm_int
. Esto protege su código contra cambios en el tamaño de therm_int
o desbordamientos de búfer accidentales. Es un pequeño ejemplo de lo que quise decir con el uso del sistema de tipos en lugar de combatirlo.
Mientras estamos en ello, eliminemos el cambio, ¡lo cual es innecesario!
for j in therm_int'reverse_range loop
if therm_int (j) = '1' then
i := j; -- last assignment is most significant '1' bit
end if;
end loop;
Tal como está escrito, esto se sintetizará para generar suficiente hardware para implementar la tarea en un solo ciclo de reloj. En general, eso llevaría a ciclos de reloj bastante lentos, y querría racionar el trabajo (quizás una iteración de bucle único por reloj). Pero esa es otra historia ...