libro - verilog bloqueante
¿Cómo interpretar las asignaciones de bloqueo versus no bloqueo en Verilog? (6)
Estoy un poco confundido acerca de cómo se interpretan las asignaciones de bloqueo y no bloqueo cuando se trata de dibujar un diagrama de hardware. ¿Tenemos que inferir que una asignación sin bloqueo nos da un registro? Entonces, de acuerdo con esta afirmación, c <= a+b
, c sería un registro correcto, pero no a y b?
module add (input logic clock,
output logic[7:0] f);
logic[7:0] a, b, c;
always_ff @(posedge clock)
begin
a = b + c;
b = c + a;
c <= a + b;
end
assign f = c;
endmodule
Definitivamente es un poco difícil entender las diferencias entre las asignaciones de bloqueo y no bloqueo inicialmente. Pero sin miedo, hay una práctica regla general:
Si desea inferir lógica combinada con un bloque
always
, use asignaciones de bloqueo (=
). Si desea una lógica secuencial, use un bloquealways
sincronizado con asignaciones sin bloqueo (<=
). Y trata de no mezclar los dos.
Su código anterior probablemente no sea el mejor ejemplo. Sin saber qué estructura de sumador / flip-flop estaba tratando de construir, existe el peligro de tener rutas de retroalimentación combinadas (que son malas). Y como no tienes buses de entrada, ¡esencialmente estás tratando de construir a
, b
& c
de la nada!
Pero para responder a su pregunta, cualquier variable asignada dentro de un bloque clocked always
inferirá un flip-flop, a menos que se le asigne mediante el operador de bloqueo ( =
) y se use como un tipo de variable local.
module add
(
input clock,
input [7:0] in1,
input [7:0] in2,
output logic [7:0] f1, f2, f3, f4, f5
);
// f1 will be a flipflop
always_ff @(posedge clock) begin
f1 = in1 + in2;
end
// f2 will be a flipflop
always_ff @(posedge clock) begin
f2 <= in1 + in2;
end
// f3 will be a flipflop
// c1 will be a flipflop
logic [7:0] c1;
always_ff @(posedge clock) begin
c1 <= in1 + in2;
f3 <= c1 + in1;
end
// f4 will be a flipflop
// c2 is used only within the always block and so is treated
// as a tmp variable and won''t be inferred as a flipflop
logic [7:0] c2;
always_ff @(posedge clock) begin
c2 = in1 + in2;
f4 = c2 + in1;
end
// c3 will be a flipflop, as it''s used outside the always block
logic [7:0] c3;
always_ff @(posedge clock) begin
c3 = in1 + in2;
end
assign f5 = c3 + in1;
endmodule
Una gran razón para seguir la regla general y no mezclar asignaciones de bloqueo y no bloqueo dentro de un bloque always
, es que mezclar sus asignaciones puede causar serias faltas de simulación entre RTL sims y gate-sims / hardware real. El simulador verilog trata =
y <=
bastante diferente. Las asignaciones de bloqueo significan ''asignar el valor a la variable de inmediato en este instante''. Las asignaciones sin bloqueo significan ''averiguar qué asignar a esta variable y almacenarla para asignarla en el futuro''. Un buen documento para leer para comprender mejor esto es: También vea: http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf
La sabiduría convencional de Verilog lo tiene todo mal. No hay problema con el uso de asignaciones de bloqueo para una variable local . Sin embargo, nunca debe usar asignaciones de bloqueo para la comunicación sincrónica, ya que esto no es determinista.
Una asignación sin bloqueo dentro de un bloque siempre sincronizado siempre inferirá un flip-flop, según lo dictado por la semántica.
Si una asignación de bloqueo dentro de un bloque siempre sincronizado infiere un flip-flop o no depende completamente de cómo se usa. Si es posible que la variable se lea antes de ser asignada, se deducirá un flip-flop. De lo contrario, esto es como una variable temporal y dará como resultado cierta lógica combinatoria.
Puedo responder a tu pregunta, pero creo que un trabajo sería lo mejor para esto, así que te recomiendo que leas este artículo de Clifford Cummings. Va a aclarar todas sus dudas y, además, fortalecerá su comprensión de verilog.
http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA_rev1_2.pdf
Solo quiero agregar a la respuesta de Jan Decaluwe. Parece que hay muy poco código en la naturaleza que realmente usa lo que Jan Decaluwe describe, aunque es absolutamente correcto. Mezclar declaraciones de bloqueo y no bloqueo es ahora un tabú, gracias a Mr.Cummings.
El problema es que la mayoría de los lugares evitan el uso de declaraciones de bloqueo para las variables locales y hay muy poco código en el espacio de búsqueda inmediata de Google que busca da un ejemplo de cómo se hace. El único lugar donde encontré el estilo de codificación mencionado por Jan es el código ganador en este artículo . Y esto, me encontré accidentalmente
Tuve un momento difícil sobre esto también.
Pero, en primer lugar, debe comprender que el bloqueo o bloqueo no tiene nada que ver con la creación de un bloqueo / ff.
Por su diferencia, podrías entenderlo simplemente (al comienzo) en este punto: i. Si usa el bloqueo, las oraciones posteriores no podrían ejecutarse hasta que el bloque asignó un valor asignado a la LHS, ya que lo que cambió a LHS podría actualizarse y usarse si se usa la variable. Sin embargo, para no bloquear, no bloquea la siguiente oración como paralelo con la siguiente oración (en realidad, el cálculo de RHS debe hacerse primero, pero no importa, ignóralo cuando confundas). El LHS no cambia / no se actualiza para la ejecución de este tiempo (se actualiza la próxima vez cuando el bloque siempre se vuelve a activar). Y después de la oración, use el valor anterior, tal como se actualizó al final del ciclo de ejecución.
a = 0; b= 0;
a = 1;
b = a;
--> output a = 1, b = 1;
a = 0; b= 0;
a <= 1;
b = a;
--> output a = 1, b = 0;
Un punto clave es encontrar si en tu código (siempre bloquear) hay cualquier variable de caso no asignada, pero podría suceder. Si no le pasa valor y ese caso ocurre, entonces se crea latch / ff para mantener el valor.
Por ejemplo,
always @(*) begin
if(in) out = 1;
else out = 0;
end
--> this end without latch/ff
always @(*) begin
if(in) out = 1;
end
--> this end with one latch/ff to keep value when in = 0, as it might happen and you didn''t assign value to out as in=1 do.
Lo siguiente también podría crear pestillo / ff:
always @(*) begin
if(in) a = 1;
else b = 1;
end
-> pestillo / ffs creado para in = 1, b sin asignación, in = 0 a sin asignación.
Además, cuando detecte posedge of clk always @(posedge clk)
, terminará con latch / ff. Porque, para clk, debe existir un borde negativo, y usted no hace nada, ¡se crean latch / ffs para mantener todo el valor anterior!
por favor, siempre puedes interpretar el verilog en el dominio digital, solo tienes que entender qué pasará si el mismo código que escribiste se convertirá en el nivel de la puerta, yo personalmente no sigo la regla de usar bloqueos en seq o usar bloqueos en combinaciones , esto limitará tu pensamiento. adhiérase al lado digital del código solo aquí es lo que sucederá si su código se convierte a nivel de compuerta simplemente vea que solo quiere esto
- primero se hará el sumador completo - entradas ayb
- la salida irá a flip-flop creando salida a teniendo sincronización con clk
- ahora, dado que la asignación se está bloqueando, entonces la nueva a se aplicará a la siguiente completa agregada que tenga esta nueva a yc como entrada, la salida de la misma irá a dffcsync para clk creando una nueva b
- ahora desde b = c + a; está allí, que está bloqueando la declaración así que b se actualiza a este nuevo b
- ahora es c <= a + b ahora lo que sucede es que se crea un sumador completo que tiene a y b como entrada que va a dff sync a clk, ahora hay otra condición como decir nuevamente a = c;
- luego se creará un dff teniendo el viejo c no el nuevo creado por la declaración de no bloqueo y el resultado de este dff sync para clk va a a y se actualiza
gracias, Rahul jain