Crear módulos combinacionales con IF-ELSE incompletos de forma que no generen latches

Diseño HDL con este lenguaje. Módulos y testbenchs. Estilos y trucos de codificación, etc. NOTA: dado que hay entornos como ISE que soportan Verilog pero no SystemVerilog, señalad dentro de un post que de lo que se va a tratar es SystemVerilog si es el caso.
Avatar de Usuario
mcleod_ideafix
Site Admin
Mensajes: 80
Registrado: 14 Ago 2018, 01:15

Crear módulos combinacionales con IF-ELSE incompletos de forma que no generen latches

Mensaje por mcleod_ideafix » 15 Ago 2018, 13:46

Esta es una traducción de un post/pregunta que hice hace ya tiempo en Stack Overflow. El texto original y las respuestas que me dieron están aquí:
https://stackoverflow.com/q/20084928/3011009

Digamos que quiero escribir un módulo combinacional que usa 4 entradas y 3 salidas. Para modelar mi lógica, hago algo como esto:

Código: Seleccionar todo

module ifelse (
      input wire a,
      input wire b,
      input wire c,
      input wire d,
      output reg y1,
      output reg y2,
      output reg y3
      );

     always @* begin

       if (a==1'b1 && b==1'b0) begin
         y1 = 1'b0;
         y3 = 1'b1;
         end
       else if (a==1'b0 && c==1'b1 && d==1'b0) begin
         y2 = 1'b1;
         y1 = 1'b1;
         end
       else if (a==1'b0 && c==1'b0) begin
         y3 = 1'b0;
         y2 = 1'b0;
       end
   end
endmodule
Por supuesto, sé que este código va a inferir latches para y1,y2 e y3, y que la forma de evitarlo es asignar siempre un valor a todas las variables en cada una de las ramas del if-else, tal que así:

Código: Seleccionar todo

module ifelse (
      input wire a,
      input wire b,
      input wire c,
      input wire d,
      output reg y1,
      output reg y2,
      output reg y3
      );

     always @* begin

       if (a==1'b1 && b==1'b0) begin
         y1 = 1'b0;
         y3 = 1'b1;
         y2 = 1'bx;
         end
       else if (a==1'b0 && c==1'b1 && d==1'b0) begin
         y2 = 1'b1;
         y1 = 1'b1;
         y3 = 1'bx;
         end
       else if (a==1'b0 && c==1'b0) begin
         y3 = 1'b0;
         y2 = 1'b0;
         y1 = 1'bx;
       end
       else begin
         y1 = 1'bx;
         y2 = 1'bx;
         y3 = 1'bx;
       end
   end
endmodule
Pero ahora imaginemos que hay un montón de bloques if-else (estoy intentando describir la unidad de control para un microprocesador didáctico) y que hay un montón de salidas que provienen de este módulo (las lineas de control para todos los registros de la ruta de datos del procesador). Tener que asignar un valor a todas las salidas en todas y cada una de las ramas del bloque if-else múltiple no es una opción, ya que da lugar a código ilegible e inmantenible. Cada vez que quiera añadir una nueva salida, tengo que replicarla en todos los if-else!!

Entonces la cuestión es: cómo dar un valor "por defecto" a las salidas cuando alguna de ellas no se usa en alguno de los bloques if-else.¿Hay algo parecido a un "default" para todas aquellas señales que no se actualizan en el bloque, de forma que una vez evaluado, si alguna salida no se ha actualizado, tome el valor "por defecto" o a un valor "don't care"?

Hasta ahora, lo que se me ha ocurrido hacer es esto:

Código: Seleccionar todo

module ifelse(
    input wire a,
    input wire b,
    input wire c,
    input wire d,
    output reg y1,
    output reg y2,
    output reg y3
    );

   always @* begin
      // default values
      y1 = 1'bx;
      y2 = 1'bx;
      y3 = 1'bx;

      if (a==1'b1 && b==1'b0) begin
         y1 = 1'b0;
         y3 = 1'b1;
      end
      else if (a==1'b0 && c==1'b1 && d==1'b0) begin
         y2 = 1'b1;
         y1 = 1'b1;
      end
      else if (a==1'b0 && c==1'b0) begin
         y3 = 1'b0;
         y2 = 1'b0;
      end
   end
endmodule
Pero querría saber si existe algo máas elegante en Verilog. Algo como esto (que no es Verilog)

Código: Seleccionar todo

module ifelse(
    input wire a,
    input wire b,
    input wire c,
    input wire d,
    output reg y1,
    output reg y2,
    output reg y3
    );

   always @* begin
      if (a==1'b1 && b==1'b0) begin
         y1 = 1'b0;
         y3 = 1'b1;
      end
      else if (a==1'b0 && c==1'b1 && d==1'b0) begin
         y2 = 1'b1;
         y1 = 1'b1;
      end
      else if (a==1'b0 && c==1'b0) begin
         y3 = 1'b0;
         y2 = 1'b0;
      end
      @* = x;  // esto no existe en Verilog. Sería para indicar que todas las salidas no actualizadas toman el valor "dont care"
   end
endmodule
Entonces... ¿existe algo parecido a esto? ¿Es lo que yo hago lo habitual, o hay una solución más elegante?

La respuesta que me dieron es que lo que yo hago es lo correcto, salvo por un detalle: que no puedo asignar un valor "x" a una variable porque "x" significa "desconocido", no "don't care". Resulta que el valor "x" sólo significa "don't care" cuando se usa como expresión en un case (realmente cuando se usa en un casex)

Responder

Volver a “Verilog / SystemVerilog”