Para empezar, la forma convencional de diseñar un flip flop JK en VHDL se vería así:
signal Q_s : std_logic;
process(clk)
begin
if (rising_edge(clk)) then
if (J = '1' and K = '1') then
Q_s <= not Q_s;
elsif(J = '1') then
Q_s <= '1';
elsif(K = '1') then
Q_s <= '0';
end if;
end if;
end process;
Q <= Q_s;
Qbar <= not Q_s;
Aquí estamos haciendo que se infiera un registro, con un comportamiento equivalente a un flip-flop JK. Tenga en cuenta que con este código, si afirma J
y K
juntos, antes de afirmar individualmente, entonces en la simulación, la salida Q
será indefinida. Si el estado inicial no importa por cualquier motivo, puede inicializarlo en la definición usando signal Q_s : std_logic := '0';
( '1'
sería igualmente válido). Si el estado inicial es importante, debe agregar una cláusula de restablecimiento específica para establecer este estado.
Volviendo a su pregunta real, en realidad no hay ningún problema con su código; se sintetizará correctamente y funcionará "correctamente", pero no dará los resultados esperados en la simulación. Puede implementar su JK flip flop de manera que ambos simulen correctamente y se puedan sintetizar con el resultado que coincida exactamente con su diagrama de circuito. Para empezar, aquí hay un banco de pruebas simple:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity tb is
end tb;
architecture a of tb is
constant CLK_PERIOD : time := 100 ns;
signal J : std_logic := '0';
signal K : std_logic := '0';
signal Clk : std_logic := '0';
signal Q : std_logic;
signal Qbar : std_logic;
begin
Clk <= not Clk after CLK_PERIOD / 2;
uut : entity work.JKFlipFlopGate
port map(
J => J,
K => K,
Clk => Clk,
Q => Q,
Qbar => Qbar
);
process
begin
wait for CLK_PERIOD;
J <= '1';
wait for CLK_PERIOD;
J <= '0';
wait for CLK_PERIOD;
k <= '1';
wait for CLK_PERIOD;
K <= '0';
wait for CLK_PERIOD;
J <= '1';
k <= '1';
wait for CLK_PERIOD;
J <= '0';
k <= '0';
wait;
end process;
end a;
El problema con la simulación de su código tal como está, es que dado que todas sus señales outx
no están inicializadas, todo el circuito se encuentra en un estado desconocido, con varias señales que tienen el valor 'U'
en el punto en que comienza la simulación. . Al agregar la inicialización, las definiciones de la señal outx
parecen:
signal out1 : std_logic := '1';
signal out2 : std_logic := '1';
signal out3 : std_logic := '0';
signal out4 : std_logic := '1';
Tenga en cuenta que estos valores de inicialización solo afectan a la simulación; ya que su código no describe ningún elemento síncrono (más bien, una función combinatoria con comportamiento similar a un elemento síncrono), no tienen impacto en el diseño sintetizado, ya sea que su cadena de herramientas los admita o no.
La simulación de este diseño actualizado funciona correctamente cuando J
o K
están configurados en '1'
. Sin embargo, cuando ambos se establecen altos, hay una condición de carrera y el circuito oscila. Esto coincide con el comportamiento del circuito real cuando el pulso del reloj permanece alto después de que la salida Q
ha cambiado. Como no hay retrasos en la descripción, esta oscilación tendrá lugar en los ciclos delta de simulación y se alcanzará el límite de iteración de la simulación. Podemos verlos más fácilmente incorporando un retardo de puerta bruto en el diseño:
entity JKFlipFlopGate is
generic(
GATE_DELAY : time := 0 ns -- Default needed for synth
);
port(
J, K, Clk : in std_logic;
Q, Qbar : out std_logic
);
end JKFlipFlopGate;
architecture result of JKFlipFlopGate is
signal out1 : std_logic := '0';
signal out2 : std_logic := '0';
signal out3 : std_logic := '1';
signal out4 : std_logic := '0';
begin
out1 <= not(J AND Clk AND out4) after GATE_DELAY;
out2 <= not(K AND Clk AND out3) after GATE_DELAY;
out3 <= out1 nand out4 after GATE_DELAY;
out4 <= out2 nand out3 after GATE_DELAY;
Q <= out3;
Qbar <= out4;
end result;
Normalmente, diría que no debe usar las cláusulas after
en el código que se implementará en hardware real, pero esto es solo un ejercicio, y estas cláusulas se ignoran por síntesis. La simulación agrega lo siguiente:
constant GATE_DELAY : time := 1 ns;
Y la instanciación uut
se convierte en:
uut : entity work.JKFlipFlopGate
generic map(
GATE_DELAY => GATE_DELAY
)
port map(
J => J,
K => K,
Clk => Clk,
Q => Q,
Qbar => Qbar
);
Ahora puede ver las oscilaciones que resultan de un pulso de reloj demasiado largo en la forma de onda de la simulación:
Podemosreducirfácilmenteelanchodelpulsodelrelojparaeliminarestasoscilacionesalagregarunanuevaseñalde'pulso',derivadadelreloj:
signalClk_pulse:std_logic:='0';
Tengaencuentaqueesteesuncódigosolodesimulación,porloquepuedeusarlosvaloresinicialescomodesee.Acontinuación,unprocesoparaderivarelpulsodereloj:
process(Clk)beginif(rising_edge(Clk))thenClk_pulse<='1','0'after2*GATE_DELAY;endif;endprocess;
Y,porúltimo,enlainstanciaciónuut
,Clk=>Clk,
seconvierteenClk=>Clk_pulse,
.
Contodosestoscambiosrealizados,eldiseñosimulaelcomportamientocorrectoyaúnsetransformacorrectamenteenelcircuitodediseñooriginal: