Regístrese comportándose como pestillo en verilog

3

Tengo el siguiente bloque de código -

always @(posedge clk) begin
    if (reset) 
        oe_hold <= 1'b0;
    else begin
         oe_hold <= 1'b0;
         if (oe && (oe_hold | we)) 
             oe_hold <= 1'b1;
    end
end

En el fragmento anterior, oe y we se controlan mediante lógica combinatoria. Supongo que si oe_hold y oe son alto , en el flanco del reloj 0 y oe baja en t = 1, entonces oe_hold bajaría en t = 2, ya que oe_hold es un registrarse y debe tomar en su entrada un ciclo más tarde.

Sin embargo, en la simulación, oe_hold se comporta como un pestillo. Baja al mismo borde del reloj que oe. Si conduzco oe en el borde negativo en el banco de pruebas, oe_hold se queda bajo en el siguiente borde del reloj (es decir, el mismo borde que bajó fue oe impulsado en el borde positivo).

¿Puede alguien explicar este comportamiento y decirme por qué ocurre?

Gracias.

Actualización 1: oe es una entrada para el dispositivo bajo prueba y se establece como tal -

@ (posedge clk) begin
    oe = 0;
end

Actualización 2:

Actualización 3: se utilizó iverilog como herramienta de simulación.

    
pregunta maverick1989

1 respuesta

1

La causa más probable, sin embargo, hasta donde puedo decir, por lo que ha publicado se debe a la forma en que está simulando el código. Sería bueno si publicaras el código que usaste para la simulación.

Es totalmente posible que si está utilizando algo como declaraciones de bloqueo para generar tanto la señal oe como la señal clk en una configuración de banco de pruebas, el simulador se confunda y desactiva oe muy poco tiempo antes El borde ascendente del reloj que no necesariamente podría ver en una vista de forma de onda (se vería como si hubiera cambiado en el borde del reloj), pero (en una simulación RTL al menos) daría como resultado el comportamiento que tiene. viendo.

En la práctica, no sucedería ya que toda la lógica, incluida la señal oe , sería sincrónica.

Voy a publicar este bit como parte de mi respuesta en lugar de un comentario, ya que permite un mejor formato de código, pero considere esta alternativa:

always @(posedge clk) begin
    if (reset) begin
        oe_hold <= 1'b0;
    end else begin
         if (oe && (oe_hold | we)) begin 
             oe_hold <= 1'b1;
         end else begin
             oe_hold <= 1'b0;
         end
    end
end

Observe cómo ahora, en lugar de intentar establecer oe_hold en \ $ 0 \ $, entonces al mismo tiempo (¡sin bloqueo!) tratando de establecerlo en \ $ 1 \ $ si el condicional era verdadero. Ahora, específicamente lo establece en \ $ 0 \ $ solo si no es cierto. El if / else es, por supuesto, equivalente a simplemente: oe_hold <= (oe && (oe_hold | we)); .

Esto puede o no puede ayudar con el problema dependiendo de cómo su software de simulación maneja la asignación conflictiva de su código. En la práctica, parece que se sintetiza lo mismo (al menos en Quartus II), pero he visto comportamientos extraños de algunos simuladores que se confunden con ciertas construcciones.

Nota: Agregué algunas declaraciones% begin / end , aunque eso fue solo para mejorar la legibilidad.

También quiero retomar algo en su pregunta, mencionó conducir una señal en un borde del reloj y otra en el borde opuesto del reloj. En lógica síncrona, debe intentar evitar esto, ya que puede llevar a problemas de tiempo en el diseño; básicamente, hace que todos sus requisitos de configuración sean dos veces más estrictos (¡porque la frecuencia de reloj efectiva se duplica!). Todo en un circuito síncrono debe estar sincronizado en el mismo borde.

    
respondido por el Tom Carpenter

Lea otras preguntas en las etiquetas