Guía Completa de $display en Verilog: Uso, Ejemplos y Técnicas de Depuración

目次

1. Introducción: Importancia y propósito de «display» en Verilog

¿Qué es «display» en Verilog?

El $display utilizado en Verilog es una de las tareas del sistema, y sirve como herramienta para «mostrar» el estado interno del programa durante la simulación. Al igual que printf en C, permite imprimir valores de señales, variables o cadenas en el terminal o consola, siendo una función muy útil que cumple un papel central en la depuración y verificación del comportamiento.

¿Por qué $display es esencial en el desarrollo con Verilog?

  • Mejora de la eficiencia en depuración: En diseños de circuitos complejos, es crucial visualizar si las señales internas funcionan correctamente. Con $display, puedes verificar instantáneamente valores durante la simulación.
  • Visualización de la simulación: Al rastrear transiciones en momentos específicos, las formas de onda pueden no ser suficientes. Los registros impresos ofrecen un medio confiable para identificar claramente esos momentos.
  • Útil para documentación: Al compartir reglas de funcionamiento o la intención del diseño con otros ingenieros, añadir anotaciones o pistas en los registros impresos mejora la comprensión del código.

Objetivo y estructura de este artículo

En este artículo, explicaremos en orden los siguientes temas:

  1. Sintaxis y uso básico: Introducción a la sintaxis y utilización fundamental de $display.
  2. Comparación con otras tareas del sistema: Diferencias frente a $write, $strobe y $monitor.
  3. Especificadores de formato y técnicas: Uso de %d, %b, %h, %s y técnicas especiales de impresión.
  4. Ejemplos prácticos: Implementaciones concretas en testbenches y módulos, con código incluido.
  5. Aplicaciones en control de pantallas: Ejemplos de uso en control de LCD o monitores, incluyendo texto e imágenes.

Con esta estructura, buscamos que tanto principiantes como usuarios intermedios comprendan correctamente el $display en Verilog y lo apliquen en la práctica. En las siguientes secciones se incluirán ejemplos y diagramas para facilitar la comprensión.

2. Lo básico de $display: sintaxis, usos y precauciones

Sintaxis básica de $display

La sintaxis general al usar $display en Verilog es la siguiente:

$display("cadena o especificadores de formato", señal1, señal2, ...);
  • Parte de la cadena: se colocan textos o especificadores de formato (ej: %d, %b, %h).
  • Argumentos: se listan señales o variables que se imprimirán según el formato indicado.

Ejemplo: mostrar el contador de reloj y valores de señales:

$display("Time=%0t : clk=%b, reset=%b", $time, clk, reset);

En este caso, se imprimen el tiempo de simulación y los valores de las señales de reloj y reset.

Usos de $display

  1. Seguimiento del progreso de la simulación
    Insertando $display en puntos clave del diseño, puedes confirmar hasta dónde ha avanzado la ejecución.
  2. Verificación de valores de señales
    Condiciones o transiciones difíciles de entender solo con formas de onda pueden interpretarse fácilmente al imprimirlas como texto.
  3. Mensajes condicionales
    Combinado con if, se pueden imprimir registros solo cuando se cumple cierta condición. if (reset) $display("Reset activado en %0t", $time);

Diferencia entre $display y $write

$display agrega automáticamente un salto de línea al final de la salida, mientras que $write no lo hace, permitiendo imprimir en línea continua.

Ejemplo:

$display("Hello");
$display("World");

Resultado:

Hello
World
$write("Hello");
$write("World");

Resultado:

HelloWorld

Si necesitas organizar registros sin saltos, usa $write. Para mostrar en líneas legibles, usa $display.

Precauciones

  1. Evitar exceso de salida
    Usar $display en cada ciclo puede generar registros enormes y poco legibles.
    → Limita la salida con condiciones.
  2. Aprovechar la impresión de tiempo
    Usa $time o $realtime para identificar con precisión el momento de la actividad.
  3. Solo para simulación
    $display no puede usarse en síntesis (FPGA/ASIC). Es exclusivo para depuración en simulación.

3. Comparación de tareas del sistema para salida de registros: $display, $write, $strobe, $monitor

Además de $display, Verilog incluye otras tareas del sistema para generar salida. Cada una difiere en su propósito y momento de impresión, por lo que entender estas diferencias es clave para una depuración eficiente.

$display: tarea estándar de impresión

  • Características
    Agrega un salto de línea automático al final, organizando la salida en líneas.
  • Usos
    El medio más común de depuración, permite imprimir en cualquier momento con una sola ejecución.

$write: impresión sin salto de línea

  • Características
    No agrega salto de línea, permitiendo concatenar texto en la misma línea.
  • Usos
    Ideal para mostrar múltiples valores en la misma línea.
  • Ejemplo $write("A=%d, ", a); $write("B=%d\n", b); → salida: A=5, B=10 en una sola línea.

$strobe: imprime valores al final del ciclo de simulación

  • Características
    Imprime valores una vez que todas las evaluaciones del ciclo actual se han estabilizado.
  • Usos
    Útil para evitar condiciones de carrera cuando múltiples señales cambian simultáneamente.
  • Ejemplo $strobe("Time=%0t, signal=%b", $time, sig); → a diferencia de $display, garantiza imprimir el valor estable.

$monitor: impresión automática en cambios de señal

  • Características
    Imprime automáticamente cada vez que las señales especificadas cambian.
  • Usos
    Conveniente para supervisar continuamente varias señales.
  • Ejemplo $monitor("At %0t: a=%b, b=%b", $time, a, b); → imprime cada vez que a o b cambian.

Resumen en tabla

TareaSalto de líneaMomento de impresiónUso principal
$displayEn el momento de la llamadaSalida básica de registros
$writeNoEn el momento de la llamadaImpresión en línea continua
$strobeTras finalizar el cicloConfirmar valores estables
$monitorEn cada cambio de señalSupervisión continua

Consejos para elegir

  • Usa $display para la mayoría de casos: legible y sencillo.
  • Usa $write cuando necesites varias impresiones en una sola línea.
  • Usa $strobe para capturar valores estables tras condiciones de carrera.
  • Usa $monitor para observación automática de señales.

4. Especificadores de formato y técnicas especiales de impresión

Con $display y $write, es posible usar “especificadores de formato” dentro de la cadena para mostrar señales y variables en distintos estilos. Se parecen mucho al printf de C, y usarlos correctamente puede aumentar la eficiencia de la depuración.

Especificadores de formato básicos

EspecificadorContenidoEjemplo de salida
%bBinario1010
%dDecimal10
%hHexadecimalA
%oOctal12
%cCaracter ASCIIA
%sCadenaHello
%tTiempo de simulación#100
%mNombre jerárquico (módulo)top.u1.u2

Ejemplos prácticos

  1. Mostrar señales en varios formatos reg [7:0] data = 8'b10101010; $display("data = %b (bin), %d (dec), %h (hex)", data, data, data); → salida: data = 10101010 (bin), 170 (dec), AA (hex)
  2. Ver jerarquía $display("Módulo actual: %m"); → salida: Módulo actual: top.u1.counter
  3. Mostrar tiempo de simulación $display("Time=%0t: clk=%b", $time, clk); → salida: Time=100: clk=1

Técnicas especiales

  • Relleno con ceros y ancho fijo
    %0d permite rellenar con ceros. $display("Count=%04d", count);Count=0012
  • Signo y sin signo
    %d trata valores con signo; %u sin signo.
  • Mensajes en varias líneas
    Puedes usar \n para saltos de línea. Ejemplo: $display("Inicio\nde prueba\nA=%b\nB=%b", A, B);

Precauciones

  • Atender al ancho de bits: los anchos distintos pueden generar truncamientos al imprimir en decimal.
  • Valores indefinidos (X, Z): %b mostrará x o z cuando estén presentes en la señal.

5. Ejemplos prácticos: uso de $display en testbenches y módulos

A continuación, veremos ejemplos reales de código Verilog que muestran cómo utilizar $display de manera efectiva, desde casos básicos hasta depuración condicional.

Ejemplo básico: salida en un testbench

Al insertar $display en un testbench, puedes verificar el comportamiento durante la simulación.

module tb_counter;
  reg clk;
  reg reset;
  wire [3:0] count;

  // DUT (Device Under Test)
  counter uut (
    .clk(clk),
    .reset(reset),
    .count(count)
  );

  // Generación de reloj
  initial begin
    clk = 0;
    forever #5 clk = ~clk;  // invertir cada 5 unidades
  end

  // Escenario de prueba
  initial begin
    reset = 1;
    #10 reset = 0;

    #50 $finish;
  end

  // Mostrar estado
  always @(posedge clk) begin
    $display("Time=%0t | reset=%b | count=%d", $time, reset, count);
  end
endmodule

En este ejemplo, cada vez que el reloj sube, se imprimen los valores de reset y count. Así se pueden verificar tanto las formas de onda como los registros de texto.

Ejemplo de impresión condicional

Combinando con if, puedes imprimir solo cuando ocurre un evento específico:

always @(posedge clk) begin
  if (count == 4'd10) begin
    $display("El contador alcanzó 10 (Time=%0t)", $time);
  end
end

→ De esta forma se evita la saturación de registros, imprimiendo solo lo relevante.

Mensajes de depuración

Al investigar bugs, es útil capturar cuando una señal toma un valor inesperado:

always @(posedge clk) begin
  if (count > 4'd12) begin
    $display("WARNING: desbordamiento detectado! Time=%0t, value=%d", $time, count);
  end
end

→ Esto permite detectar fallos en el diseño o comportamientos no previstos en simulación.

Supervisión de múltiples señales

Cuando se manejan muchas señales, agruparlas en una sola línea con $display mejora la legibilidad:

$display("Time=%0t | clk=%b | reset=%b | A=%h | B=%h | SUM=%h",
         $time, clk, reset, A, B, SUM);

Resumen de puntos prácticos

  • Inserta en testbenches para visualizar el progreso de la simulación.
  • Usa condiciones para filtrar mensajes.
  • Muestra advertencias para detectar errores.
  • Agrupa múltiples señales en una sola línea para mayor claridad.

6. Aplicaciones del control de pantallas (píxeles, texto e imágenes)

Hasta ahora, hemos visto $display como una función de salida de texto en simulaciones.
Por otro lado, Verilog también se usa para control de pantallas en FPGA (LCD, VGA, HDMI). A continuación se presentan conceptos básicos.

Conceptos básicos de control de pantallas

Para mostrar texto o imágenes en un monitor, no basta con $display. Es necesario generar señales de video:

  • HSYNC (sincronización horizontal): delimita cada línea.
  • VSYNC (sincronización vertical): delimita cada cuadro.
  • Datos RGB: definen el color de cada píxel (ej: 24 bits = 8×3).

En Verilog, se usan contadores y máquinas de estado para generar estas señales en sincronía con el reloj.

Ejemplo 1: mostrar barras de color

always @(posedge clk) begin
  if (h_counter < 100)       rgb <= 24'hFF0000; // rojo
  else if (h_counter < 200)  rgb <= 24'h00FF00; // verde
  else if (h_counter < 300)  rgb <= 24'h0000FF; // azul
  else                       rgb <= 24'h000000; // negro
end

→ Esto genera barras rojas, verdes y azules en la pantalla.

Ejemplo 2: mostrar texto

Para texto, se usa una ROM de fuentes que convierte códigos de caracteres en patrones de píxeles:

// Mostrar la letra 'A'
if (font_rom[char_code][y][x] == 1'b1)
    rgb <= 24'hFFFFFF;  // blanco
else
    rgb <= 24'h000000;  // negro

→ Así se dibuja un carácter en la pantalla.

Ejemplo 3: mostrar imágenes

Para imágenes, se cargan datos de un bitmap en ROM o memoria externa:

rgb <= image_rom[addr];  // leer datos de color

Esto permite mostrar íconos o logotipos simples en FPGA.

Diferencias con $display

  • $display: salida de texto para simulación (no sintetizable).
  • Control de pantalla: generación de señales de video (síntesis en FPGA).

Comparación:

  • “Quiero depurar en simulación” → usa $display.
  • “Quiero mostrar en un monitor real” → diseña lógica de video en Verilog.

Aplicaciones avanzadas

  • En placas FPGA educativas, es común usar 7 segmentos o LCDs pequeños.
  • Con más experiencia, se puede generar VGA/HDMI para juegos o GUIs.
  • Combinando $display y control de pantalla, puedes depurar tanto en simulación como en hardware real.

7. Uso adecuado según el contexto y consejos prácticos

En Verilog, la palabra “display” puede referirse tanto a las tareas de simulación ($display y relacionadas) como al control de pantallas en hardware. Usarlas de forma adecuada en cada contexto mejora la eficiencia del desarrollo.

Uso en simulación

  1. $display como registro de depuración
    • Imprime variables y señales clave para verificar que el diseño funcione correctamente.
    • Es especialmente útil para condiciones específicas o alcanzar ciertos valores de contador.
  2. Evitar salidas excesivas
    • Si imprimes en cada ciclo, los registros se saturan.
    • Ejemplo: if (state == ERROR) $display("Error detectado en %0t", $time);
  3. Elegir la tarea correcta
    • $monitor: seguimiento automático de señales.
    • $strobe: imprimir valores estables al final del ciclo.
    • $write: impresión continua en una sola línea.

Uso en hardware real

  1. Visualización en 7 segmentos
    • En proyectos básicos, mostrar contadores en LEDs de 7 segmentos es típico.
    • Combinarlo con $display en simulación facilita el aprendizaje.
  2. Control de LCD o VGA
    • Usar ROM de fuentes o imágenes para mostrar texto e íconos.
    • Verificar la generación de señales con $display antes de probar en FPGA.
  3. Superposición para depuración
    • En FPGA avanzados, se pueden superponer mensajes de depuración en la salida de video.
    • Esto convierte la propia pantalla en una herramienta de verificación.

Consejos prácticos

  • Sigue el flujo simulación → hardware
    Primero depura con $display, luego implementa la lógica de video.
  • Combina registros y formas de onda
    Los registros de texto muestran eventos; el visor de ondas, las transiciones.
  • Unifica formatos de mensaje
    En equipos de trabajo, estandariza el estilo de salida de $display.

Resumen

  • $display y tareas relacionadas son herramientas de observación en simulación.
  • El control de pantallas es implementación en hardware.
  • Usar ambos de forma complementaria permite un desarrollo más eficiente.

8. FAQ (Preguntas frecuentes)

Q1. ¿Cuál es la diferencia entre $display y $monitor?

A. $display imprime solo cuando se invoca. $monitor imprime automáticamente cada vez que cambian las señales registradas.

  • Depuración puntual → $display
  • Supervisión continua → $monitor

Q2. ¿Cuándo usar $strobe?

A. Úsalo cuando quieras capturar el valor estable tras el final de un ciclo de simulación. Evita mostrar valores intermedios en condiciones de carrera.

Q3. ¿Para qué sirve el especificador %m?

A. Imprime el nombre jerárquico del módulo actual. Es muy útil en diseños grandes para identificar el origen del mensaje.

$display("Módulo actual: %m");

Ejemplo de salida:

Módulo actual: top.u1.counter

Q4. ¿Qué hacer si tengo demasiadas salidas de $display?

A. Usa estas técnicas:

  • Condicionar con if.
  • Imprimir solo errores o eventos clave.
  • Supervisar un conjunto mínimo con $monitor.
  • Exportar a archivo y filtrar después.

Q5. ¿Se puede usar $display en síntesis (FPGA/ASIC)?

A. No. $display es exclusivo de simulación. No se implementa en hardware real.

Q6. ¿Cómo mostrar texto o imágenes en hardware?

A. Generando señales de video, no con $display:

  • 7 segmentos → mostrar números.
  • VGA/LCD → generar HSYNC, VSYNC y señales RGB.
  • Texto → usar ROM de fuentes.
  • Imágenes → cargar datos de bitmap en memoria.

9. Conclusión y próximos pasos

Resumen del artículo

En este artículo hemos explicado el uso de $display en Verilog desde lo básico hasta aplicaciones avanzadas:

  1. Conceptos básicos: $display imprime señales y variables en simulación, similar a printf en C.
  2. Diferencias con otras tareas: $write, $strobe, $monitor.
  3. Especificadores de formato: %b, %d, %h, %m, %t, etc.
  4. Ejemplos prácticos: testbenches, mensajes condicionales y advertencias.
  5. Aplicaciones en hardware: desde 7 segmentos hasta VGA/HDMI en FPGA.

Próximos pasos

  • Explorar SystemVerilog
    Incluye funciones de depuración más avanzadas como assertions.
  • Combinar con visores de ondas
    Los registros de $display y las formas de onda se complementan.
  • Practicar en hardware
    Prueba pequeños proyectos de salida en FPGA (LCD o 7 segmentos).
  • Trabajo en equipo
    Estandariza el formato de mensajes de $display para análisis colaborativo.

Palabras finales

$display es mucho más que un simple comando de impresión: es una herramienta poderosa de depuración en simulación. Y, al aprender control de pantallas, Verilog también permite llevar gráficos a hardware real mediante FPGA.

Esperamos que este artículo ayude a los lectores a comprender tanto el aspecto de simulación como el de implementación práctica en Verilog.