¿Es posible hacer un flip flop D con reinicio activado por nivel asíncrono?

Estoy empezando a aprender la codificación Verilog en la universidad y no tuve tanto problema hasta ahora. Creo que tengo los conceptos básicos a la perfección. Pero acabo de golpear una pared de ladrillos con este. Estaba experimentando con modelos de comportamiento y terminé teniendo este problema.

Es fácil hacer un flip flop D con reinicio activado por nivel síncrono como este

always @(posedge clk)
begin
    if(clr) begin
        q <= 1'b0;
    end
    else begin
        q <= d;
    end
end

O hacer un flip flop D con reinicio activado por borde síncrono como este

always @(posedge clk or posedge clr)
begin
    if(clr) begin
        q <= 1'b0;
    end
    else begin
        q <= d;
    end
end

Pero, ¿cómo puedo hacer que un nivel se active pero se reinicie de forma asíncrona? No puedo hacerlo

always @(posedge clk or clr)

porque eso sería orear dos tipos incompatibles, por lo que se generará un error al realizar la síntesis RTL. No puedo hacerlo

always @(posedge clk)
begin
    q <= d;
end

always @(clr)
begin
    q <= 1'b0;
end

ya que eso requeriría múltiples fuentes para impulsar q, nuevamente problema en la síntesis RTL.

Entonces, mi pregunta es, ¿es posible o no hacer un D-flip flop con reinicio activado por nivel asíncrono? Tanto en verilog como en lógica digital.

Respuestas (4)

Aquí está el ejemplo de Xilinx de un "Flip-Flop con reloj de borde negativo y reinicio asíncrono":

always @(negedge C or posedge CLR)
    begin
        if (CLR)
            Q <= 1’b0;
        else
            Q <= D;
    end

(Fuente: Guía de diseño de síntesis y simulación, UG626, 19 de octubre de 2011)

Tenga en cuenta que esto es básicamente lo mismo que su segundo ejemplo (excepto que usa el borde del reloj opuesto). Y, de hecho, este es un borrado sensible al nivel, no un borrado sensible al borde, porque si el borrado se mantiene alto, la salida continuará manteniéndose baja, incluso si llegan nuevos bordes de reloj y/o cambia la entrada D.

¿Tal especificación, escrita como se indica arriba, proporciona alguna indicación sobre si el circuito es necesario para evitar fallas en la salida o un comportamiento extraño si llegan pulsos de reinicio o de reloj malformados mientras D y Q son ambos cero? Una primitiva de flip flop de hardware que incluyera un reinicio asíncrono naturalmente no tendría problemas con tales cosas, pero evitar tales problemas al sintetizar un flop de reinicio asíncrono a partir de otras primitivas requeriría circuitos adicionales.
@supercat, No, nada en Verilog le dice qué sucede si las señales de entrada no están en niveles lógicos válidos, por ejemplo. Pero, si su herramienta de síntesis es buena, y hay tal cosa disponible en su arquitectura (como en un FPGA de Xilinx), el código escrito aquí se sintetizará en un flip-flop de hardware con reinicio asíncrono, no en un flip-flop construido fuera de las puertas. De hecho, este es exactamente el código que Xilinx recomienda si desea sintetizar un flip-flop de hardware.
Si el hardware que se conecta a un dispositivo puede emitir señales con niveles lógicos o tiempos no válidos en casos que "no deberían" importar, ¿hay alguna forma de especificar que un dispositivo debe ignorar tales entradas? Por ejemplo, si una placa tuviera un 74HC74 y un FPGA con algunos pines de repuesto, y uno quisiera absorber la función del 74HC74 en el FPGA, y si el circuito que conducía el 74HC74 a veces emitiera pulsos cortos en la línea de configuración o reinicio en los casos en que la salida ya estaba en el estado correcto, ¿podría especificarse que el sintetizador debe producir algo que funcione correctamente?
Incluso si algunas partes tienen ambos flops primitivos con async-set y async-clear, algunas solo tienen una entrada asíncrona. Si no hubiera un flop primitivo asíncrono-establecido-claro, uno podría sintetizar uno usando un flop asíncrono-claro para rastrear si el último evento significativo fue un reloj o una señal asíncrona, y alimentar eso en un mux junto con el último bit sincronizado e indicador de si "set" o "clear" estuvo activo en último lugar, pero dicha implementación podría fallar si hubiera un reinicio/liberación asíncrono limpio, seguido de un "1" limpio registrado, seguido de un conjunto asíncrono runt, aunque un 74HC74 no tendría problema.
@supercat, Verilog es una herramienta puramente digital. El lenguaje Verilog no tiene concepto de niveles lógicos inválidos (hay símbolos de "no importa" y "alta impedancia", pero no resuelven su problema). El trabajo del diseñador de celdas lógicas es determinar el comportamiento de las entradas no válidas, si es necesario. Ese tipo de trabajo probablemente se haría con un simulador tipo SPICE, no con Verilog.
@supercat, es trabajo del diseñador lógico diseñar usando solo el subconjunto de Verilog que se puede sintetizar. Qué subconjunto depende exactamente de qué hardware y qué herramienta de síntesis está utilizando. Si desea diseñar un flip-flop con set y clear en una arquitectura que solo tiene una entrada de control, entonces debe investigar si su herramienta de síntesis puede manejar eso o no. Mi experiencia es que es mejor asumir que la herramienta de síntesis es muy tonta y solo usa estilos de codificación muy bien documentados; de lo contrario, incluso si logra que algo funcione, podría romperse en la próxima revisión de sw.
El simulador puede predecir si un diseño sintetizado funcionará, pero si uno descubre a partir de la simulación que se necesita lógica adicional para suprimir una falla de salida no deseada cuando llega un borde en lo que debería ser una entrada indiferente, o uno tiene una diseño que casi encaja, y podría encajar si a uno no le importaran las fallas de salida en ciertos casos, parecería que uno querría poder alterar el comportamiento del sintetizador en tales casos.
Entiendo el concepto de restringir el diseño de uno a las cosas que sintetizarán bien, pero eso parecería negar el propósito de usar un lenguaje de alto nivel en primer lugar. Parecería más útil poder decir "Necesito que esta salida se comporte limpiamente de acuerdo con esta fórmula, eliminando los peligros", y "esta salida puede hacer lo que quiera hasta que todas estas entradas sean estables", y hacer que el sintetizador genere lógica adicional en el primer caso según sea necesario. ¿Las herramientas simplemente no están ahí todavía?

No estoy muy familiarizado con Verilog, pero según tengo entendido, algunas herramientas de síntesis chillarán ante los intentos de generar lógica sintetizada síncrona y asíncrona en plataformas de hardware cuyas primitivas no admiten tales cosas. Es posible producir un circuito que se comporte como un flip-flop de reinicio asíncrono, siempre que los bordes de reinicio no ocurran cerca de los bordes del reloj. Aquí hay un ejemplo. Sin embargo, una cosa importante a tener en cuenta con este circuito es que, si bien se garantiza que un reinicio asincrónico de hardware eliminará cualquier metaestabilidad, un circuito que simula uno no ofrece tal garantía.

No estoy seguro de verilog, pero en VHDL pensé que sería algo como esto:

ARCHITECTURE behavioral OF dff_asynch IS 
BEGIN  
 PROCESS(D, Clk, Clr, Pre) 
 BEGIN 
  IF Clr = '0' THEN  -- Don’t wait for clock 
   Q <= '0'; 
   Qbar <= '1'; 
  ELSIF Pre = '0' THEN 
   Q <= '1'; 
   Qbar <= '0'; 
  ELSIF (Clk'event) AND (Clk='1') THEN   -- Positive Edge 
   Q <= D; 
   Qbar <= not D; 
  END IF; 
 END PROCES

1) Sin reinicio: siempre @(negedge C) comienzan Q <= D; fin

2) Reinicio síncrono siempre @(negedge C) comienza si (CLR) // Si C no se está ejecutando, un cambio en CLR no afecta a QQ <= 1'b0; si no Q <= D; fin

3) Reinicio asíncrono siempre @(negedge C o posedge CLR) comienzan si (CLR) Q <= 1'b0; si no Q <= D; fin