Arreglos en Verilog: Guía completa con ejemplos prácticos para principiantes y avanzados

目次

1. Introducción

Verilog es un lenguaje de descripción de hardware ampliamente utilizado y resulta esencial en el diseño de circuitos como FPGA o ASIC. Para realizar un diseño eficiente con Verilog, la comprensión de los arreglos es sumamente importante.

El uso de arreglos permite manejar conjuntos de datos de manera concisa e intuitiva, lo que mejora la legibilidad y el mantenimiento del código. En particular, cuando se requiere agrupar múltiples señales o representar estructuras de memoria como la RAM, los arreglos resultan muy efectivos.

En este artículo, nos centraremos en la palabra clave «arreglos en Verilog» y explicaremos desde la definición básica hasta técnicas prácticas de aplicación en proyectos reales. Cubriremos los tipos de arreglos, las extensiones de SystemVerilog, así como errores comunes y preguntas frecuentes, con el objetivo de profundizar la comprensión del lector.

El contenido está pensado para principiantes, e incluye ejemplos de código prácticos, de modo que podrás seguirlo fácilmente hasta el final.

2. Tipos de datos básicos en Verilog

Antes de trabajar con arreglos en Verilog, es necesario comprender los tipos de datos básicos. Verilog proporciona varios tipos principales diseñados para manejar señales lógicas en el diseño de circuitos.

Diferencias entre reg y wire

Los tipos de datos más comunes en Verilog son reg (registro) y wire (cable). Se utilizan de manera distinta según el comportamiento de las señales lógicas.

  • wire
    wire se utiliza como una línea de conexión entre módulos o circuitos. Siempre debe estar conducido por otra señal, y la asignación se realiza con la sentencia assign. Es adecuado para salidas de circuitos combinacionales. Ejemplo:
  wire a;
  assign a = b & c;
  • reg
    reg se utiliza como una variable que almacena temporalmente un valor. Se asigna dentro de bloques de proceso (como always) y representa elementos de memoria como biestables o flip-flops. Ejemplo:
  reg q;
  always @(posedge clk) begin
      q <= d;
  end

Tipos de datos para arreglos

En Verilog, los arreglos se definen principalmente con reg, aunque en algunos casos también es posible usar wire. No obstante, en las primeras versiones de Verilog existían limitaciones como la falta de soporte para arreglos multidimensionales. Estas restricciones se resolvieron en gran medida con SystemVerilog.

Ejemplo de sintaxis básica para definir un arreglo:

reg [7:0] data_array [0:15];  // Arreglo de 16 elementos de 8 bits

Comprender los fundamentos de los tipos de datos ayuda a evitar confusiones en la declaración y uso de arreglos. Una mala elección entre reg y wire puede provocar errores en la simulación o la síntesis lógica.

3. Conceptos básicos de los arreglos

En Verilog, los arreglos se utilizan cuando se desea manejar varias señales del mismo tipo de manera conjunta. Con ellos, es posible organizar señales y mejorar la legibilidad y reutilización del código.

Declaración de arreglos

En Verilog se soportan principalmente arreglos unidimensionales, con la siguiente sintaxis:

reg [ancho_de_bits] nombre_arreglo [rango_de_indice];

Ejemplo específico:

reg [7:0] data_array [0:15];  // Arreglo de 16 elementos de 8 bits

Aquí, data_array tiene 16 elementos indexados de 0 a 15, cada uno con un ancho de 8 bits (1 byte).

Acceso a elementos de un arreglo

Cada elemento de un arreglo se accede mediante un índice. Al igual que en C, la indexación comienza en 0.

data_array[0] = 8'hFF;   // Asigna 0xFF al primer elemento
data_array[1] = 8'd12;   // Asigna 12 decimal al segundo elemento

También es posible inicializar o modificar los elementos dentro de un bloque always usando bucles.

integer i;
always @(posedge clk) begin
    for (i = 0; i < 16; i = i + 1) begin
        data_array[i] <= 8'd0;
    end
end

Ventajas de los arreglos

  • Procesamiento en bloque: combinados con bucles for, permiten aplicar la misma operación a múltiples señales de forma simultánea.
  • Estructuración del circuito: facilitan la organización de registros y señales, manteniendo una arquitectura clara.
  • Implementación de modelos de memoria: pueden representar estructuras como RAM o ROM directamente en el código (se explicará más adelante).

Puntos a tener en cuenta

En Verilog no se admite la asignación directa a todo el arreglo (data_array = valor). Solo es posible operar a nivel de cada elemento. Además, originalmente solo se soportaban arreglos unidimensionales; para usar arreglos multidimensionales se requiere Verilog 2001 o SystemVerilog.

4. Uso de arreglos multidimensionales

El uso de arreglos multidimensionales en Verilog permite manejar estructuras de datos más complejas de manera eficiente y simplificar el diseño del circuito.

No obstante, es importante mencionar que en Verilog IEEE 1364-1995 no se admitían arreglos multidimensionales. Fueron introducidos oficialmente a partir de Verilog 2001. Para operaciones aún más flexibles, se recomienda el uso de SystemVerilog.

Declaración de arreglos multidimensionales

A partir de Verilog 2001 es posible declarar un arreglo con varios índices para una misma variable. Ejemplo:

reg [7:0] matrix [0:3][0:3];  // Matriz de 4x4 elementos de 8 bits

Con esta declaración, matrix contiene 16 elementos, organizados en un arreglo bidimensional.

Acceso y asignación de elementos

Los arreglos multidimensionales también permiten el acceso mediante índices para asignar valores específicos:

matrix[0][0] = 8'hA5;
matrix[2][3] = 8'd255;

Uso de bucles for anidados

Los arreglos multidimensionales se manipulan de forma flexible con bucles anidados. Ejemplo de inicialización:

integer i, j;
always @(posedge clk) begin
    for (i = 0; i < 4; i = i + 1) begin
        for (j = 0; j < 4; j = j + 1) begin
            matrix[i][j] <= 8'd0;
        end
    end
end

Aplicaciones de los arreglos multidimensionales

  • Diseños que requieren operaciones matriciales o filtros.
  • Procesamiento de imágenes o señales digitales (DSP), con manipulación de datos por píxeles.
  • Organización de bloques de ROM/RAM o asociación de direcciones con pares de datos.

Limitaciones y consideraciones

  • Es necesario verificar la compatibilidad de la herramienta de síntesis, ya que algunas no admiten completamente arreglos multidimensionales.
  • Pueden existir restricciones al combinarlos con instanciación de módulos o interfaces.
  • Conviene conocer las diferencias con SystemVerilog para evitar problemas de compatibilidad.

5. Modelado de memoria con arreglos

En Verilog es posible modelar estructuras de memoria de manera sencilla utilizando arreglos. De esta forma, se pueden simular y diseñar circuitos de almacenamiento como RAM o ROM.

En particular, los modelos de memoria basados en arreglos unidimensionales se emplean con frecuencia en el diseño de CPUs y sistemas de comunicación.

Sintaxis básica de un modelo de memoria

Ejemplo de una RAM de 32 bits × 1024 direcciones (0–1023):

reg [31:0] memory [0:1023];  // Memoria de 32 bits × 1024 palabras

Con esta declaración, el arreglo memory puede almacenar 1024 palabras de 32 bits, accesibles mediante índices (direcciones).

Lectura y escritura en memoria

Las operaciones de lectura y escritura en memoria se describen de la siguiente forma:

// Escritura
always @(posedge clk) begin
    if (we) begin
        memory[addr] <= data_in;
    end
end

// Lectura
assign data_out = memory[addr];

Puntos clave:

  • La escritura ocurre de forma sincronizada al flanco positivo de clk, condicionada por we (write enable).
  • La lectura suele implementarse como una operación combinacional mediante assign.

Inicialización de memoria

Para bancos de pruebas o para definir el estado inicial, es posible inicializar el arreglo con un bloque initial:

integer i;
initial begin
    for (i = 0; i < 1024; i = i + 1) begin
        memory[i] = 32'd0;
    end
end

También es posible cargar valores desde archivos externos usando $readmemh o $readmemb:

initial begin
    $readmemh("rom_init.hex", memory);  // Inicializa en formato hexadecimal
end

Aplicaciones prácticas

  • Registros de CPU o microcontroladores
  • Simulación del comportamiento de BRAM dentro de FPGAs
  • Verificación del funcionamiento de memorias caché
  • Lectura de datos almacenados en ROM

Consideraciones

  • El tamaño del arreglo influye directamente en el tiempo de simulación y recursos de síntesis.
  • El momento de lectura (sincrónica o asincrónica) debe definirse según las especificaciones del diseño y las herramientas utilizadas.
  • Para síntesis, es recomendable seguir las guías de inferencia de memoria de cada proveedor.

6. Extensiones de arreglos en SystemVerilog

Hasta Verilog 2001, la funcionalidad de arreglos era limitada, lo que complicaba los diseños. Con la llegada de SystemVerilog, se ampliaron considerablemente las posibilidades, permitiendo una codificación más flexible y potente.

En esta sección exploraremos tres tipos principales de arreglos disponibles en SystemVerilog: arreglos dinámicos, arreglos asociativos y colas (queues).

Arreglos dinámicos

Características

  • Pueden cambiar de tamaño en tiempo de ejecución.
  • Son útiles cuando el tamaño del arreglo es desconocido o variable.

Declaración y uso

int dyn_array[];             // Declaración de arreglo dinámico
dyn_array = new[10];         // Inicialización con 10 elementos
dyn_array[0] = 100;

Casos de uso

  • Almacenamiento temporal de datos en bancos de pruebas
  • Gestión de buffers de tamaño variable

Arreglos asociativos

Características

  • El índice puede ser un valor arbitrario (entero, cadena, etc.).
  • Funcionan como tablas hash.

Declaración y uso

int assoc_array[string];     // Arreglo asociativo con claves tipo string
assoc_array["id_001"] = 42;

Casos de uso

  • Gestión de parámetros configurables
  • Almacenamiento de valores indexados por ID o nombre

Colas (Queues)

Características

  • Tienen comportamiento de tipo FIFO (First-In-First-Out).
  • Permiten añadir y eliminar elementos fácilmente, ideales para secuencias dinámicas.

Declaración y uso

int queue_array[$];          // Declaración de cola

queue_array.push_back(10);   // Agregar al final
queue_array.push_front(5);   // Agregar al inicio
int val = queue_array.pop_front();  // Extraer desde el inicio

Casos de uso

  • Almacenamiento temporal en buffers FIFO
  • Gestión de eventos o transacciones

Comparación y uso recomendado

Tipo de arregloRedimensionamientoTipo de índiceUso recomendado
DinámicoPermitidoEnteroCuando el tamaño no está definido de antemano
AsociativoPermitidoArbitrario (int, string, etc.)Cuando se requiere búsqueda estilo hash
ColaPermitidoAutomático (inicio/fin)Cuando se agregan o eliminan elementos frecuentemente

Consideraciones

  • Estas estructuras son propias de SystemVerilog y no están disponibles en Verilog estándar.
  • Su síntesis depende de las herramientas, pero suelen usarse principalmente en bancos de pruebas.
  • En proyectos destinados a FPGA o ASIC, es fundamental confirmar si son compatibles antes de utilizarlos.

7. Mejores prácticas en la manipulación de arreglos

Al trabajar con arreglos en Verilog o SystemVerilog, es fundamental mantener un código eficiente y legible. Esta sección presenta una serie de buenas prácticas para garantizar un diseño de hardware claro y seguro.

Aclarar la intención con nombres y comentarios

Los arreglos pueden dificultar la interpretación de lo que representa cada elemento. Por ello, conviene seguir estas recomendaciones:

  • Usar nombres descriptivos: reg [7:0] sensor_data [0:7];
  • Agregar comentarios claros sobre su uso y unidades:
// Arreglo que almacena 8 datos de sensores de 8 bits
reg [7:0] sensor_data [0:7];

Cuidar las condiciones de los bucles

Al usar bucles for con arreglos, se debe verificar la validez de los límites para evitar accesos fuera de rango.

  • Un límite mal definido puede causar accesos inválidos o advertencias en simulación.
  • La elección entre < y <= debe hacerse con cuidado.

Ejemplo:

integer i;
always @(posedge clk) begin
    for (i = 0; i < 8; i = i + 1) begin
        sensor_data[i] <= 8'd0;
    end
end

Inicializar explícitamente

Un arreglo sin inicialización puede introducir valores indefinidos en la simulación. Esto puede afectar especialmente a memorias o bancos de registros.

initial begin
    for (i = 0; i < 256; i = i + 1)
        mem[i] = 32'd0;
end

En SystemVerilog, la inicialización puede simplificarse con foreach o constructores.

Diseñar módulos reutilizables

Los arreglos permiten escalabilidad en el diseño. Para aumentar la reutilización, se recomienda:

  • Usar parámetros que definan el tamaño del arreglo:
parameter DEPTH = 16;
reg [7:0] buffer [0:DEPTH-1];

De esta manera, el módulo se adapta a distintas configuraciones sin modificar el código base.

Considerar la síntesis

Es importante tener en cuenta la compatibilidad con las herramientas de síntesis:

  • Los arreglos unidimensionales con reg son ampliamente soportados.
  • Los arreglos dinámicos, asociativos o colas de SystemVerilog son no sintetizables y se usan principalmente en simulación.

Para hardware real, se debe priorizar el uso de estructuras compatibles con los compiladores de FPGA o ASIC.

Equilibrar arreglos y modularidad

Aunque los arreglos reducen líneas de código, en diseños grandes puede ser preferible dividir el sistema en módulos independientes.

  • Para operaciones repetitivas simples: usar arreglos y bucles.
  • Para funciones distintas o sistemas grandes: crear módulos separados y jerárquicos.

8. Preguntas frecuentes (FAQ)

Durante el uso de arreglos en Verilog y SystemVerilog, existen dudas comunes entre principiantes e intermedios. A continuación, respondemos a tres de las más habituales:

Q1. ¿Por qué aparece un error al usar arreglos multidimensionales en Verilog?

A1.

Porque en Verilog 1995 y versiones anteriores a Verilog 2001, no se admitían arreglos multidimensionales o estaban muy limitados.

Por ejemplo, este código es válido solo desde Verilog 2001:

reg [7:0] matrix [0:3][0:3];  // Soportado desde Verilog 2001

Solución:

  • Confirmar que la herramienta soporte Verilog 2001 o posterior.
  • Si no, representar la matriz con un arreglo unidimensional:
reg [7:0] matrix_1d [0:15];  // Acceso usando (i*4 + j)

Q2. ¿Un RAM escrito con arreglos en Verilog funciona en hardware real?

A2.

Sí. Muchos sintetizadores soportan RAM descrita con arreglos:

reg [31:0] mem [0:255];  // RAM de 32 bits × 256 palabras

Advertencias:

  • Debe ajustarse a las plantillas de inferencia de cada herramienta.
  • El tipo de lectura/escritura (sincrónica o asincrónica) influye en cómo se sintetiza.

Q3. ¿Pueden sintetizarse arreglos dinámicos, asociativos o colas en SystemVerilog?

A3.

No. Estos arreglos son exclusivos para simulación. No se traducen directamente a hardware.

Se usan en:

  • Bancos de pruebas
  • Entornos de verificación
  • Modelos de transacciones

Para hardware real, es necesario convertirlos a reg o a arreglos de tamaño fijo.

9. Conclusión

En este artículo hemos explorado el tema de los arreglos en Verilog, desde los conceptos básicos hasta aplicaciones avanzadas. El uso correcto de arreglos contribuye directamente a la eficiencia, legibilidad y mantenibilidad del diseño de hardware.

Puntos clave del artículo

  • Comprender los tipos de datos básicos de Verilog (reg y wire) es esencial para evitar errores en el uso de arreglos.
  • Los arreglos unidimensionales son fundamentales para agrupar datos o modelar memorias simples.
  • Los arreglos multidimensionales fueron introducidos en Verilog 2001 y permiten representar estructuras como matrices.
  • SystemVerilog amplió estas capacidades con arreglos dinámicos, asociativos y colas, útiles en entornos de verificación.
  • Aplicar las mejores prácticas (inicialización, comentarios claros, modularidad y consideración de la síntesis) mejora la calidad del diseño.

Consejos prácticos

Si bien los arreglos son herramientas poderosas, no siempre deben aplicarse indiscriminadamente. En proyectos destinados a hardware real, es crucial respetar las limitaciones de síntesis y las guías de estilo. Para simulación y verificación, SystemVerilog ofrece estructuras más avanzadas que optimizan la productividad.

El buen diseñador sabe elegir la herramienta adecuada: arreglos simples para hardware sintetizable y estructuras avanzadas para entornos de prueba.

Siguientes temas recomendados

Si ya comprendes los fundamentos de los arreglos, puedes avanzar hacia los siguientes tópicos:

  • Uso de la sentencia generate para crear arreglos de instancias de manera dinámica.
  • Combinación de interface con arreglos para el diseño de buses.
  • Implementación de estructuras como FIFO, buffers circulares y memorias ROM optimizadas.

Dominar los arreglos es un paso fundamental en el camino de todo diseñador de Verilog. Con práctica y experiencia, podrás abordar proyectos de mayor complejidad y escalar tus habilidades hacia un diseño digital más profesional.