Creé un módulo Verilog simple que muestra números aleatorios. Este módulo tiene un contador que cuenta en cada borde del reloj y con solo presionar un botón, se muestra el número que esté en el contador en ese momento. Aquí está mi código:
module counter (input wire in, input wire clock, input wire reset, output reg [3:0] number)
reg [3:0] cur_state;
reg [3:0] next_state;
always @ (posedge clock) begin
if (reset) cur_state <= 4'b0;
else cur_state <= next_state;
end
// next state function
always @ (*) begin
next_state = cur_state + 4'b1;
end
// output
always @ (*) begin
if (in) number = cur_state;
end
number[3:0] se envía a un módulo de visualización para mostrar el número correspondiente. (Las entradas se eliminan correctamente).
Todo funciona bien en la FPGA, pero el programa me notifica que he usado un pestillo en la salida. ¿Hay alguna forma de prevenir esto e implementar el mismo comportamiento usando un flip-flop?
Gracias.
Su problema radica en que está describiendo un circuito asíncrono que requiere su estado anterior.
// output
always @ (*) begin
if (in) number = cur_state;
end
Cuando in
es alto, todo está bien - number
se le asigna el valor de cur_state
. Sin embargo, ¿qué sucede cuando in
es bajo?
Cuando in
es bajo, number
no tiene un nuevo valor especificado (es decir, a través de else
), lo que significa que está infiriendo que debe mantener su valor. Cada vez que se le pide a un circuito combinacional que mantenga su valor, obtiene un pestillo.
Entonces, la forma de evitar bloqueos es asegurarse de que en cada lógica inferida de forma combinada, defina completamente el valor asignado para que nunca se requiera. Puede hacer esto de una de dos maneras.
Primero, si no le importa el valor cuando in
es bajo, puede asignar alguna constante:
// output
always @ (*) begin
if (in) begin
number = cur_state; //If in is high, output the current state
end else begin
number = 4'b0000; //If in is low, output is don't care so avoid latch by assigning value
end
end
En segundo lugar, si necesita que la salida mantenga su estado, debe convertirlo en un proceso cronometrado:
// output
always @ (posedge clock) begin
if (in) number = cur_state;
end
Ahora que es síncrono, puede hacer que la salida mantenga su estado porque ahora está infiriendo un flip-flop. La desventaja de esto es que tiene una latencia de 1 ciclo desde que cambia la in
señal hasta que number
se actualiza el valor.
Las respuestas de la combinación de @Tom Carpenter y @toolic son casi correctas. Necesita las asignaciones sin bloqueo si desea evitar problemas de simulación de eventos combinacionales que ocurren después de eventos secuenciales. La asignación sin bloqueo se asegura de eso.
Otra cosa que es importante agregar es que la entrada de entrada es una señal asíncrona y, por lo tanto, si se muestrea, debe muestrearse a través de un sincronizador de doble flop como mínimo.
He reescrito su código con un solo registro para mantener el estado de su FSM.
module counter (input wire in, input wire clock, input wire reset, output reg number);
reg cur_state;
reg next_state;
always @ (posedge clock) begin
if (reset) cur_state <= 4'b0;
else cur_state <= next_state;
end
// next state function
always @ (*) begin
next_state = cur_state + 1'b1;
end
// output
always @ (*) begin
if (in) number = cur_state;
end
endmodule
Así se sintetiza tu código usando Yosys
Esto tiene sentido, ya que estamos describiendo un FSM con un solo registro [un solo flip flop 1] para almacenar el estado y en cada flanco positivo del reloj, la entrada en este flip flop es una salida de circuito combinacional [que agrega 1 al estado actual] .
Esto se describe con estos dos bloques funcionales.
always @ (posedge clock) begin
if (reset) cur_state <= 4'b0;
else cur_state <= next_state;
end
// next state function
always @ (*) begin
next_state = cur_state + 1'b1;
end
El problema principal ahora está en el DLatch final que retiene su salida
always @ (*) begin
if (in) number = cur_state;
end
Esto se debe a que el bloque de código anterior describe un DLatch. Siempre que IN == 1 deje que la salida = el estado actual, y siempre que IN == 0 no cambie la salida.
Esto se traduce en un Dlatch en el que la puerta del pestillo [El EN] está conectada a la entrada IN y la entrada de este DLatch está conectada al estado actual.
Como se mencionó anteriormente, puede corregir esta mala interpretación usando una declaración else en el último bloque siempre.
always @ (*) begin
if (in) number = cur_state;
else number=0;
end
Ahora tu así es como se sintetiza el código. Puede ver que la salida ahora es impulsada por una puerta AND, no por un pestillo.
Estoy bastante seguro de que las respuestas anteriores ya mencionaron esto, pero creo que observar cómo se sintetiza su circuito hace una gran diferencia.
number
cuando in
es bajo, ¿puedo asignarlo 4'bx
como valor constante, para que quede explícito que no me importa? Si es así, aunque no me importa, ¿cuál podría ser el valor de salida "real"? ¿Habría alguna diferencia si uso 4'bz
para configurarlo en alta impedancia, o no se recomienda aquí?
tom carpintero
always @ (*) begin if (in) number = cur_state;
¿ Qué pasa cuandoin
está bajo?AyudanteRey
tom carpintero