Solo por diversión, quería diseñar y simular flip-flops tipo D usando solo lógica combinacional en Verilog (o SystemVerilog). Estoy usando Verilator para la simulación.
Mi intento inicial, que usa un diseño clásico de seis NAND, parece funcionar bien y ha pasado todas las pruebas. Mi segundo intento, basado en un tipo JK de cuatro NAND, no funciona. La salida no permanece bloqueada durante el nivel positivo del reloj y, para algunas pruebas, la simulación ni siquiera converge.
P: Sé que no es normal ni óptimo, pero ¿es razonable diseñar flip-flops usando lógica combinacional en Verilog? Si es así, ¿hay algún problema con mi segundo diseño?
Este funciona:
module dff( input clk, input D, output Q );
wire a, sn, rn, b, Qn;
always_comb // captures D @( posedge clk )
begin
a = !(b&sn);
sn = !(a&clk);
rn = !(sn&b&clk);
b = !(rn&D);
Q = !(sn&Qn);
Qn = !(rn&Q);
end
endmodule
Este no funciona:
module dff( input clk, input D, output Q );
wire J=D, K=!D;
wire sn, rn, qn;
always_comb // captures D @( posedge clk ), but fails to hold
begin
sn = !(J&clk&qn);
rn = !(K&clk&Q);
Q = !(sn&qn);
qn = !(rn&Q);
end
endmodule
En un esfuerzo por eliminar la asignación de bloqueo y las listas de sensibilidad , volví a implementar el enfoque basado en JK de la siguiente manera, pero las formas de onda de salida no se vieron afectadas por esta diferencia.
module dff( input clk, input D, output Q );
wire J=D, K=!D;
wire sn, rn, qn;
assign sn = !(J&clk&qn);
assign rn = !(K&clk&Q);
assign Q = !(sn&qn);
assign qn = !(rn&Q);
endmodule
Nota: basé el diseño de estos en las descripciones y diagramas aquí .
El JK que tiene es un pestillo, no un disparador de borde. También falta la retroalimentación entre Q y qn (a su primer código también le falta esta retroalimentación). Combinacional siempre bloquea el trabajo en función de la lista de sensibilidad. La lista de sensibilidad automática de always @*
y always_comb` está determinada por las señales que se usan en el lado derecho de una expresión y no en el lado izquierdo.
Si declara la lista de sensibilidad, debería funcionar: always @( J,K,clk, Q,qn )
de esta manera, Q y qn volverán a activar el bloqueo siempre.
Otro enfoque es usar una declaración de caso:
always_comb
if (clk)
Q = Qpre;
else
case({J,K})
2'b10 : Qpre = 1'b1;
2'b01 : Qpre = 1'b0;
2'd11 : Qpre = ~Q;
default : Qpre = Qpre; // no change
endcase
El problema con el uso de la lógica combinacional para los fracasos es que puede haber violaciones del tiempo de espera. Verilog un simulador indeterminado. Esto significa que no se garantiza el orden en que se evalúa un bloque siempre. Usando el siguiente código como ejemplo. Verilog puede ejecutarse b_combff
antes c_combff
, por lo que c
se le asignará el valor de a
. Esto se debe a que estamos utilizando asignaciones de bloqueo. El simulador también podría ejecutarse c_combff
antes b_combff
y obtendremos el valor correcto. Ambos escenarios son legales.
dff b_combff(.Q(b), .clk(clk), .D(a);
dff c_combff(.Q(c), .clk(clk), .D(b);
Una asignación sin bloqueo bien ubicada ( <=
) en Q puede ayudar. Esto separará la evaluación y la actualización en regiones separadas del programador. Esto corrige la condición de carrera del tiempo de espera pero no ayuda con la síntesis.
Los sintetizadores modernos son inteligentes, pero no son brillantes. Buscan patrones de codificación para determinar cómo convertir RTL en puertas equivalentes. Cuando lo vean, always @
se convertirán en chanclas sensibles a los bordes. Funcionan bien con pestillos SR, RS y D muy simples. Biond que tratan de hacer lógica combinacional. Cuando agrega sus propios fracasos personalizados, el sintetizador intentará hacerlo coincidir con la lógica que ya conoce, lo que probablemente dará como resultado una lógica de bloqueo asincrónico.
En resumen, es posible diseñar flip-flops usando lógica combinacional, pero fuera del aprendizaje generalmente no es una buena idea.
always_comb
inferir que la lista de sensibilidad son todas las variables de las declaraciones contenidas? ¿Quizás está insinuando que las asignaciones de bloqueo son el único problema, y los problemas de enganche/retroalimentación se derivan de eso?wire
tipos en un bloque siempre. Cliff escribe grandes artículos; Me refiero a ellos también cuando me enfrento a desafíos más allá de LRM. El IEEE Std 1800-2012 es la última especificación oficial de SystemVerilog. Y para su información: también puede probar otros simuladores en EDAplayground .Las descripciones del flip-flop JK tienden a ser muy confusas. En particular, la interacción con el reloj rara vez parece describirse de una manera completamente coherente, pero esto puede deberse en gran medida a un problema mayor de uso de terminología impreciso y ambiguo .
El problema básico con el flip-flop JK de la pregunta se describe en esta respuesta . En resumen, lo que se modela no se activa por el borde, a pesar de las indicaciones de lo contrario en el artículo de Wikipedia al que se hace referencia .
Para construir un flip-flop JK activado por borde, puede usar una configuración de dos etapas de pestillos en cascada (lo que se denomina "maestro-esclavo"), de modo que las dos etapas estén en estado transparente frente a estado de espera durante fases de reloj opuestas. . En este arreglo, la primera etapa mantendrá los datos estables mientras que la segunda etapa está en su estado transparente. Esta relación crea el efecto edge-trigger y se implementa a continuación...
module dff( input clk, input D, output Q );
wire Q1;
jkff A(!clk,D,!D,Q1);
jkff B(clk,Q1,!Q1,Q);
endmodule
...dónde jkff
está la misma lógica que antes (pero sería mejor llamarlo "cerrojo cerrado JK")...
module jkff( input clk, input J, input K, output Q );
wire sn, rn, qn;
always_comb
begin
sn = !(J&clk&qn);
rn = !(K&clk&Q);
Q = !(sn&qn);
qn = !(rn&Q);
end
endmodule
La falta de convergencia informada puede explicarse por el modo de alternar no convergente del diseño activado por nivel, si se permitiera que las entradas mantuvieran el estado (J=K=1).
De mayor interés: El libro "Verilog HDL", de Samir Palnitkar, incluye una implementación de un flip-flop tipo D que es prácticamente equivalente al que se muestra en la pregunta.
Entonces, para ser explícito: la respuesta a la pregunta inicial es: sí, esto es algo razonable de hacer. Sin embargo, no hay garantía de que algún hardware en particular pueda realizar tales diseños. Los diferentes simuladores también pueden dar resultados diferentes, especialmente con respecto a la distinción entre simulación previa y posterior a la síntesis.
ben voigt