Verilog siempre se bloquea sin posicionar o negar

2

Tengo un bloque Verilog básico que escribí para desencadenar cualquier cambio en la señal.

always @ (trigger)  
begin  
  data_out <= data_in;  
end

Esperaba que esto se disparara en el borde ascendente o descendente del gatillo. En su lugar, vinculó data_out a data_in. Incluso cuando el disparador estaba en estado estable, la salida estaba cambiando con la entrada. ¿Qué me estoy perdiendo aquí?

EDITAR: solo puedo usar las tres señales enumeradas: data_in, data_out y trigger. La salida debe iniciarse en el giro del bit del activador.

    
pregunta Snagglewhen

3 respuestas

3

No estoy seguro de por qué se activaría en data_in cuando se escribiera así a menos que lo sintetices y simules en el nivel de la puerta.

always @(posedge clk) en RTL se asigna a un flip-flop.

always @* en RTL se asigna a lógica combinatoria.

El @* es una lista de sensibilidad autocompletada basada en cualquier señal que pueda afectar a una salida (lado izquierdo de =).

Su uso de especificar manualmente una lista de sensibilidad que no se usa, para crear un valor de salida no es válido para la síntesis. Como no se asigna al hardware.

NB: solo debes usar <= dentro de always @posedge blocks (cuando impliques flip-flops) de otra manera usa = .

Puede crearse un circuito de detección de bordes que se pueda usar como habilitación para un sistema con reloj.

//Capture Previous trigger values
reg [1:0] trigger_d;
always @(posedge clk) begin
  trigger_d = {trigger_d[0], trigger};
end

reg trigger_toggle;
always @* begin
  //Bitwise XOR reduction operator creates pos & neg edge detect.
  trigger_toggle = ^trigger_d; 
end

always @(posedge clk) begin
  if (trigger_toggle) begin
    data_out <= data_in;  
  end
end

Haga un seguimiento de la pregunta publicada en el comentario para el sistema sin reloj dedicado:

 logic pos_enable =1'b0;
 logic neg_enable =1'b0;
 always @(posedge trigger) begin
    data_1     <= data_in;  
    pos_enable <= ~pos_enable;
 end

 always @(negedge trigger) begin
    data_2     <= data_in;  
    neg_enable <= ~neg_enable:
 end

 wire sel = pos_enable ^ neg_enable;
 always @* begin
  if (sel) begin
   data_out = data_1;
  end
  else begin
   data_out = data_2;
  end
 end
    
respondido por el pre_randomize
2

No debería haber un problema con la simulación. Habrá un problema al sintetizar, lo que generará un comportamiento de paso en lugar de ser sincronizado a través de doble borde. La mayoría de los sintetizadores no admiten el reloj de doble borde y los que lo hacen a menudo requieren una configuración y restricción especiales. Consulte el manual y otra documentación del sintetizador / FPGA.

En general, always @ (trigger) no se sintetizará en un flip flop de doble borde. Si su sintetizador admite flops de doble filo, intente: always @ (posedge trigger or negedge trigger) . Esto lo hace más explícito para los eventos de borde. La herramienta de síntesis puede requerir requisitos adicionales, como declarar el disparador como un reloj de velocidad de datos dual. Si no cumple con los requisitos de los sintetizadores para identificar flops de doble borde, podría inferir uno de los bordes como desencadenante asíncrono de nivel de configuración / reinicio.

SystemVerilog simplificó el cronometraje para eventos de doble borde. Sin embargo, incluso si SystemVerilog es compatible, algunos proveedores no han implementado el soporte para esta función. Si es compatible con su sistema, intente: always_ff @(edge trigger) . Es más comparativo y explícito que declarar ambos bordes en la lista de sensibilidad y debería generar la misma lógica.

    
respondido por el Greg
0

Como otros ya han señalado en sus respuestas, los elementos no relacionados con el borde de la lista de sensibilidad se ignoran en la síntesis. No solo se hace de esta manera en general mediante herramientas de síntesis, sino que es parte del estándar de síntesis IEEE Verilog RTL (IEEE 1364.1, no IEEE 1364, tenga en cuenta que no existe un estándar de síntesis para System Verilog IEEE 1800).

Greg mencionó el soporte para los flops de doble filo en algunas herramientas. Los flops de doble borde no son compatibles con el estándar y, por lo tanto, estas son características no estándar. No puedes esperar que una herramienta de síntesis lo admita.

Sin embargo, si realmente necesitas un flop de doble filo y no quieres depender de características no estándar, y no quieres instanciar directamente una primitiva de celda, entonces siempre puedes usar el siguiente artilugio:

module dual_edge_ff(trig, din, dout);
    input trig;
    input din;
    output dout;

    reg qpos = 0, qneg = 0;

    always @(posedge trig)  
        if (dout != din)
            qpos <= ~qpos;

    always @(negedge trig)  
        if (dout != din)
            qneg <= ~qneg;

    assign dout = qpos ^ qneg;
endmodule

Las inicializaciones (qpos = 0, qneg = 0) solo están ahí para la simulación, de modo que el módulo no emita la constante 'x'.

    
respondido por el CliffordVienna

Lea otras preguntas en las etiquetas