Soy un principiante completo con VHDL y casi un principiante con lógica digital y tengo un problema para leer un libro que estoy leyendo. En particular, un ejercicio solicita construir un contador con una habilitación y un interruptor de reinicio. Lo implementé de una manera y el compilador (Xilinx ISE) se quejó de ello lo suficiente como para tomar el camino de menor resistencia y cambiarlo a algo que pensé que era subóptimo. Pero ahora me gustaría saber qué está mal con mi código original.
Aquí está el ejemplo 'trabajando':
-- EXAMPLE 1
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity clocks is
Port (
switch0 : in STD_LOGIC;
switch1 : in STD_LOGIC;
LEDs : out STD_LOGIC_VECTOR (7 downto 0);
clk : in STD_LOGIC
);
end clocks;
architecture Behavioral of clocks is
signal counter : STD_LOGIC_VECTOR( 29 downto 0 ) := ( others => '0' );
begin
LEDs <= counter( 29 downto 22 );
clk_proc: process( clk, switch1, switch0 )
begin
if rising_edge( clk ) then
if switch0 = '1' then
counter <= counter + 1;
elsif switch1 = '1' then
counter <= ( others => '0' );
end if;
end if;
end process;
end Behavioral;
Básicamente, establece el interruptor 0 y el contador comienza a contar. Borrar el switch0 y deja de contar. Establezca el switch1 mientras el switch0 está despejado y el contador se reiniciará a 0. Establezca el switch1 mientras el switch0 esté configurado y el contador no se reinicie.
Lo que realmente quería era que el interruptor de reinicio1 pudiera borrar el contador incluso si se configuraba el interruptor0. Quería que el flanco ascendente del interruptor de reinicio1 restableciera el contador de nuevo a 0, mientras que el contador sigue subiendo si el interruptor de habilitación 0 aún está configurado.
Pensé que podría acercarme un poco más cambiando el proceso a esto:
-- EXAMPLE 2
clk_proc: process( clk, switch1, switch0 )
begin
if rising_edge( clk ) then
if switch1 = '1' then
counter <= ( others => '0' );
elsif switch0 = '1' then
counter <= counter + 1;
end if;
end if;
end process;
Pero, extrañamente, en el chip Spartan 6 que estoy usando, ¿el interruptor de habilitación0 sigue anulando el interruptor de reinicio1? Entonces intenté esto:
-- EXAMPLE 3
clk_proc: process( clk, switch1, switch0 )
begin
if rising_edge( switch1 ) then
counter <= ( others => '0' );
else
if rising_edge( clk ) then
if switch0 = '1' then
counter <= counter + 1;
end if;
end if;
end if;
end process;
Este debería ser exactamente lo que quiero, pero Xilinx ISE está aún menos satisfecho con esto: recibo estas advertencias del compilador:
WARNING:Xst:647 - Input <switch0> is never used. This port will be preserved and left unconnected if it belongs to a top-level block or it belongs to a sub-block and the hierarchy of this sub-block is preserved.
WARNING:Xst:647 - Input <clk> is never used. This port will be preserved and left unconnected if it belongs to a top-level block or it belongs to a sub-block and the hierarchy of this sub-block is preserved.
WARNING:Xst:2404 - FFs/Latches <counter<1:30>> (without init value) have a constant value of 0 in block <clocks>.
WARNING:Par:288 - The signal clk_IBUF has no load. PAR will not attempt to route this signal.
WARNING:Par:288 - The signal switch0_IBUF has no load. PAR will not attempt to route this signal.
WARNING:Par:288 - The signal switch1_IBUF has no load. PAR will not attempt to route this signal.
WARNING:Par:283 - There are 3 loadless signals in this design. This design will cause Bitgen to issue DRC warnings.
switch0 nunca se usa? Tampoco es clk? ¿A dónde fueron? Y cuando lo ejecuté en mi Spartan 6, hizo lo mismo que el ejemplo 'de trabajo'. Intenté esto también:
-- EXAMPLE 4
clk_proc: process( clk, switch1, switch0 )
begin
if rising_edge( switch1 ) then
counter <= ( others => '0' );
end if;
if rising_edge( clk ) then
if switch0 = '1' then
counter <= counter + 1;
end if;
end if;
end process;
Esto ni siquiera se integrará en la implementación. Recibo estas advertencias / errores:
WARNING:Xst:647 - Input <clk> is never used. This port will be preserved and left unconnected if it belongs to a top-level block or it belongs to a sub-block and the hierarchy of this sub-block is preserved.
WARNING:Xst:3002 - This design contains one or more registers/latches that are directly
incompatible with the Spartan6 architecture. The two primary causes of this is
either a register or latch described with both an asynchronous set and
asynchronous reset, or a register or latch described with an asynchronous
set or reset which however has an initialization value of the opposite
polarity (i.e. asynchronous reset with an initialization value of 1).
¿Alguien me puede dar una idea de qué se trata de estos procesos re-trabajados que no son kosher? Entiendo que hay muchas cosas que se pueden codificar en VHDL pero que no se pueden traducir a un diseño de hardware, y la segunda de mis revisiones parece caer en esa categoría, pero ¿puede alguien explicarme lo que está pasando aquí? ? ¿Qué pasa con un pestillo con restablecimientos async y conjuntos? ¿Qué hay de malo con los bloques anidados if-then-end? ¿Qué estoy haciendo mal aquí?
ACTUALIZACIÓN: como en la respuesta, los ejemplos 3 y 4 nunca podrían haber funcionado porque un proceso no puede cronometrarse varias veces; solo puede tener una señal con un evento rising_edge () o 'en él. Resulta que el ejemplo 2 realmente funciona y hace lo que yo quiero que haga. Lo pasé por el simulador y me pareció bien, y cuando lo sinteticé nuevamente para el hardware, funcionó bien en mi Spartan 6. ¿Debo haber hecho algo extraño la primera vez que lo probé?