Verilog impidiendo pestillos

1

Creé un módulo simple de Verilog que muestra números aleatorios. Este módulo tiene un contador que cuenta en cada borde del reloj y al presionar un botón, se muestra el número que se encuentre 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

el número [3: 0] se envía a un módulo de pantalla para mostrar el número correspondiente. (Las entradas se anuncian correctamente).

Todo funciona bien en el FPGA, pero el programa me notifica que he usado un pestillo en la salida. ¿Hay alguna forma de evitar esto e implementar el mismo comportamiento utilizando un flip-flop?

Gracias.

    
pregunta HelperKing

3 respuestas

2

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 asigna al 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á inferiendo que debe mantener su valor. Cada vez que se solicita a un circuito combinado que mantenga su valor, se obtiene un cierre.

La forma de evitar los latches es asegurarse de que en cada lógica de deducción combinada, defina completamente el valor asignado para que nunca se requiera. Puedes hacer esto de una de las dos maneras.

Primero, si no te importa el valor cuando in es bajo, entonces puedes 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 está sincronizado, puede hacer que la salida mantenga su estado porque ahora está inferiendo un flip-flop. La desventaja de esto es que tienes una latencia de 1 ciclo desde que cambias la señal in a cuando se actualiza el valor number .

    
respondido por el Tom Carpenter
1

La combinación de respuestas de @Tom Carpenter y @toolic es casi correcta. Necesita las asignaciones no bloqueantes si desea evitar problemas de simulación de eventos combinacionales que suceden después de eventos secuenciales. La asignación no bloqueante se asegura de eso.

Otra cosa que es importante agregar es que la entrada es una señal asíncrona y, por lo tanto, si se toma una muestra, se debe muestrear a través de un mínimo de un sincronizador de doble flop.

    
respondido por el Guy Regev
1

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í es como se sintetiza su código utilizando Yosys

Estotienesentido,yaqueestamosdescribiendounFSMconunsoloregistro[Single1flipflop]paraalmacenarelestadoyencadaflancopositivodelrelojlaentradaenesteflipflopesunasalidadecircuitocombinacional[queagrega1alaestadoactual].

Estosedescribeconestosdosbloquesfuncionales

always@(posedgeclock)beginif(reset)cur_state<=4'b0;elsecur_state<=next_state;end//nextstatefunctionalways@(*)beginnext_state=cur_state+1'b1;end

ElproblemaprincipalahoraestáenelDLatchfinalquetienesusalida

always@(*)beginif(in)number=cur_state;end

EstosedebeaqueelbloquedecódigoanteriorestádescribiendounDLatch.SiemprequeIN==1dejequelasalida=elestadoactual,ycuandoIN==0nocambielasalida.

EstosetraduceenunDlatchenelquelapuertadelpestillo[LaEN]estáconectadaalaentradaINylaentradadeesteDLatchestáconectadaalestadoactual.

Comosemencionóanteriormente,puedecorregirestamalainterpretaciónutilizandounainstrucciónelseenelúltimobloquesiempre

always@(*)beginif(in)number=cur_state;elsenumber=0;end

Ahora,asíescomosesintetizaelcódigo.PuedeverquelasalidaahoraestácontroladaporunacompuertaANDnounpestillo.

Estoy bastante seguro de que las respuestas anteriores ya mencionaron esto, pero creo que ver cómo se sintetiza su circuito hace una gran diferencia.

    
respondido por el Elbehery

Lea otras preguntas en las etiquetas