Conducir una pantalla de 7 segmentos con un registro frente a un cable

Hace unos días, cuando obtuve mi FPGA, creé un módulo para controlar mi pantalla de 7 segmentos. Usé solo asignaciones continuas para controlar los leds.

module set_number(input [3:0] x, output [6:0] seg);
    assign seg = x == 0 ? 7'b1000000 :
                 x == 1 ? 7'b1111001 :
                 x == 2 ? 7'b0100100 :
                 x == 3 ? 7'b0110000 :
                 x == 4 ? 7'b0011001 :
                 x == 5 ? 7'b0010010 :
                 x == 6 ? 7'b0000010 :
                 x == 7 ? 7'b1111000 :
                 x == 8 ? 7'b0000000 :
                 x == 9 ? 7'b0010000 : 
                          7'b1111111;
endmodule

Estaba leyendo un libro y tienen una pantalla de 7 segmentos escrita así usando registros y un bloque siempre combinacional.

module hex_to_sseg
(
 input  wire  [3:0]  hex,
 input  wire  dp,
 output  reg  [7:0]  sseg   // output active low
);

always @*
begin
   case(hex)
      4'h0:  sseg[6:0]  = 7'b0000001;
      4'h1:  sseg[6:0]  = 7'b1001111;
      4'h2:  sseg[6:0]  = 7'b0010010;
      4'h3:  sseg[6:0]  = 7'b0000110;
      4'h4:  sseg[6:0]  = 7'b1001100;
      4'h5:  sseg[6:0]  = 7'b0100100;
      4'h6:  sseg[6:0]  = 7'b0100000;
      4'h7:  sseg[6:0]  = 7'b0001111;
      4'h8:  sseg[6:0]  = 7'b0000000;
      4'h9:  sseg[6:0]  = 7'b0000100;
      4'ha:  sseg[6:0]  = 7'b0001000;
      4'hb:  sseg[6:0]  = 7'b1100000;
      4'hc:  sseg[6:0]  = 7'b0110001;
      4'hd:  sseg[6:0]  = 7'b1000010;
      4'he:  sseg[6:0]  = 7'b0110000;
      default:  sseg[6:0]  = 7'b0111000;   //4'hf
  endcase
  sseg[7] = dp;

¿Hay alguna diferencia práctica entre mi enfoque con el cable y el enfoque del libro con el registro y la lógica combinacional?

Respuestas (4)

Como menciona transistor en su respuesta, la lógica representada por las dos piezas de código que publicaste no es la misma; tiene diferencias en el orden de los bits y la última muestra mostrará caracteres hexadecimales AF.

Pero, está preguntando sobre la diferencia entre usar una variable de cable y una declaración de asignación frente a una variable de registro y una construcción siempre @ *.

Una cosa confusa sobre verilog es que usar un tipo de datos reg en su código no siempre implica que se implementará un registro en la lógica sintetizada.

En los casos que publicó, ambas soluciones se implementarían utilizando lógica combinatoria sin registros físicos. Es muy común usar la construcción always @* para modelar la lógica combinatoria.

Los circuitos secuenciales, que incluirán registros físicos (flip-flops), también se modelan utilizando la construcción siempre, pero estos circuitos tendrán una señal posedge y/o negedge especificada en la lista de sensibilidad.

De los casos que publicaste, personalmente preferiría usar la versión siempre @* del código, ya que creo que muestra más claramente la intención del código; es fácil ver que representa una tabla de decodificación.

Esta es exactamente la razón por la que SystemVerilog reemplazó la regpalabra clave con logic go.mentor.com/wire-vs-reg

Muchos sintetizadores utilizan el operador condicional de tratamiento ( ?:) como mux 2:1 explícito. Operadores condicionales anidados con sintetizar a medida que se escribe el diseño. En tu caso, será una cadena de diez musas 2:1. Aquí hay un diagrama de su código sintetizado con Yosys 0.3.0 en edaplayground

con declaración de asignación

Al convertir su código en una declaración de caso, se sintetizará de la siguiente manera (también sintetizado con Yosys 0.3.0 en edaplayground ). En este caso, Yosys usó un multiplexor de prioridad, pero podría haber elegido fácilmente un

con declaración de caso en un bloque siempre

Funcionalmente los dos son idénticos. La versión de declaración de caso generalmente tendrá una sincronización mejor y más uniforme. Con los operadores condicionales anidados, cuando x==0el retardo de prórroga es de 2 puertas lógicas, cuando x>=9es de 11 puertas lógicas. La versión de declaración de caso también le da al sintetizador más flexibilidad, lo que le permite elegir las mejores opciones para la situación teniendo en cuenta los recursos disponibles, los recursos necesarios para otra lógica y los requisitos de tiempo.

En general, es mejor usar una declaración de caso y dejar que el sintetizador escoja los multiplexores apropiados.

Hay varias formas diferentes de expresar la misma descripción en Verilog. La assigndeclaración continua es buena para escribir una ecuación para una sola señal, pero en realidad no es RTL. Si desea asignar varias señales en función del mismo conjunto de entradas, el alwaysbloque le permite mostrar el flujo de decisiones tomadas en un bloque de código de procedimiento. Esta es una manera mucho mejor de mostrar su intención mediante el uso de un conjunto de declaraciones RTL más legibles por humanos.

Si su preocupación es con respecto a los valores binarios, entonces se ve bien. El código de ejemplo tiene dos diferencias.

  • El orden de los bits se invierte. Esto se puede reorganizar para adaptarse al diseño de PCB.
  • La versión del libro mostrará el conjunto completo de caracteres hexadecimales, mientras que la suya solo maneja dígitos decimales.
  • El libro parece estar usando un registro de salida diferente.
Entiendo esas diferencias. Simplemente no entiendo por qué el libro usa un bloque siempre con un registro cuando puedes hacerlo mucho más simplemente con asignar.
Lo siento, no sé nada de eso. A ver quién más se apunta.