Entender sentencias assign en Verilog: Asignación continua de señales explicada
Señales de tipo wire o tipos similares requieren asignación continua de valor. Por ejemplo, un cable eléctrico en protoboard: mientras se aplique +5V a un extremo, el componente en el otro extremo recibirá el voltaje.

En Verilog, esto se realiza con la sentencia assign donde cualquier wire o tipo similar puede impulsarse continuamente con un valor (constante o expresión de señales).
Sintaxis de assign
La sintaxis empieza con assign seguido del nombre de señal (individual o concatenación de nets). Drive strength y delay son opcionales y se usan más para modelado de flujo de datos que para síntesis real. La expresión o señal del lado derecho se evalúa y asigna al net o expresión de nets del lado izquierdo.
assign <net_expression> = [drive_strength] [delay] <expresión de señales o valor constante>
Valores de delay son útiles para especificar retardos de puertas y modelar comportamiento temporal en hardware real porque dictan cuándo el net debe asignarse con el valor evaluado.
Reglas
- LHS debe ser siempre net escalar/vector o concatenación de estos, nunca registro escalar/vector.
- RHS puede contener registros escalares/vectores y llamadas a funciones.
- Cuando cualquier operando en RHS cambia valor, LHS se actualiza con el nuevo valor.
- Sentencias
assignse llaman asignaciones continuas y están siempre activas.
Ejemplo #1
En el siguiente ejemplo, un net out es impulsado continuamente por expresión de señales i1 y i2 con AND lógico &.

Si los wires se convierten en puertos y se sintetizan, obtendremos esquema RTL como el siguiente.

Ejemplo #2
El módulo siguiente toma dos entradas y usa assign para impulsar salida z usando part-select y concatenaciones multi-bit. Trata cada caso como único código en el módulo, sino múltiples assign en la misma señal harán que la salida sea X.
module xyz (
input [3:0] x, // x vector 4-bit
input y, // y escalar (1-bit)
output [4:0] z // z vector 5-bit
);
wire [1:0] a;
wire b;
// Asume una de las siguientes asignaciones en diseño real
// Si x='hC y y='h1 veamos valor de z
// Caso #1: 4 bits de x y 1 de y concatenados -> 5-bit net asignado a z. z='b11001 o 'h19
assign z = {x, y};
// Caso #2: mismo pero asignado a 3 bits seleccionados de z. 2 bits restantes undriven -> high-imp. z='bZ001Z
assign z[3:1] = {x, y};
// Caso #3: bit4 de z impulsado con constante 1. Ahora z = 'b1001Z (solo bit0 undriven)
assign z[3:1] = {x, y};
assign z[4] = 1;
// Caso #4: bit3 impulsado en su lugar, dos drivers para bit3 con mismo valor 0. Sin contención, z = 'bZ001Z
assign z[3:1] = {x, y};
assign z[3] = 0;
// Caso #5: bit3 impulsado con 1, dos drivers con valores distintos (primero X=0, segundo 1). Desconocido cuál gana. z='bZX01Z
assign z[3:1] = {x, y};
assign z[3] = 1;
// Caso #6: Selección parcial de operandos en RHS, solo 2 bits de x, z = 'b00001 (z[4:3] = 0)
assign z = {x[1:0], y};
// Caso #7: Asignar solo 3 bits de z y dejar resto sin conectar -> z = 'bZZ001
assign z[2:0] = {x[1:0], y};
// Caso #8: Misma variable múltiples veces, z = 'b00111. 3{y} = {y, y, y}
assign z = {3{y}};
// Caso #9: LHS concatenado: a 2-bit, b escalar. RHS=11001, LHS 3-bit -> primeros 3 bits LSB de RHS a LHS. a='b00, b='b1
assign {a, b} = {x, y};
// Caso #10: Invertir orden en LHS manteniendo RHS -> a='b01, b='b0
assign {b, a} = {x, y};
endmodule
Asignar variables reg
Es ilegal impulsar o asignar variables reg con assign. Esto es porque reg almacena datos y no requiere impulso continuo. Señales reg solo pueden impulsarse en bloques procedimentales initial y always.
Asignación Continua Implícita
Cuando assign asigna valor a net, es explícita. Verilog también permite asignación al declarar el net, llamada implícita.
wire [1:0] a;
assign a = x & y; // Asignación explícita
wire [1:0] a = x & y; // Asignación implícita
Diseño de Lógica Combinacional
Considera el siguiente circuito digital de puertas combinacionales y su código Verilog.

La lógica combinacional requiere entradas impulsadas continuamente para mantener salida, a diferencia de elementos secuenciales como flip-flops donde el valor se captura y almacena en flanco de clock. assign encaja bien porque la salida o se actualiza cuando cualquier entrada en RHS cambia.
// Módulo con 4 entradas, operación booleana, salida en o
module combo (
input a, b, c, d,
output o
);
assign o = ~((a & b) | c ^ d);
endmodule
Esquema de Hardware
Tras elaboración y síntesis, obtenemos circuito combinacional que se comporta igual que el modelo assign.

La señal o se vuelve 1 cuando expresión RHS es verdadera, 0 cuando falsa. o es X de 0ns a 10ns porque entradas son X en ese tiempo.

Verilog
- Dominando la sentencia switch en C#: Sintaxis, ejemplos y mejores prácticas
- Sentencia break en C#: Cómo y cuándo usarla
- Dominando la sentencia continue en C#: Cómo saltar iteraciones de bucles eficazmente
- Dominar la concatenación en Verilog: Guía práctica
- Comprender las asignaciones en Verilog: tipos, sintaxis y mejores prácticas
- Bloqueante vs. No bloqueante en Verilog: Diferencias clave explicadas
- Dominar las funciones en Verilog para diseño RTL eficiente
- Comprender las Tasks en Verilog: Funciones vs Tasks, sintaxis y uso
- Generador de reloj en Verilog: Guía de diseño e implementación
- Dominar las funciones matemáticas en Verilog para diseño de hardware eficiente
- Dominar $timeformat en Verilog: Control de precisión y visualización