Diseñar lógica combinacional en Verilog usando sentencias assign continuas
La sentencia assign de Verilog se usa típicamente para impulsar continuamente señales de tipo wire y se sintetiza como lógica combinacional. Aquí más ejemplos de diseño usando assign.
Ejemplo #1: Lógica combinacional simple
El código implementa lógica combinacional simple con salida z impulsada continuamente con assign para realizar la ecuación digital.
module combo (
input a, b, c, d, e,
output z
);
assign z = ((a & b) | (c ^ d) & ~e);
endmodule
El módulo combo se elabora en el siguiente esquema hardware usando herramientas de síntesis, implementando la lógica con puertas digitales.

Testbench
El testbench simula el diseño para verificar comportamiento esperado. Todas las combinaciones de entradas se aplican al módulo con un bucle for y delay de 10 unidades de tiempo.
module tb;
reg a, b, c, d, e;
wire z;
integer i;
combo u0 ( .a(a), .b(b), .c(c), .d(d), .e(e), .z(z));
initial begin
a <= 0; b <= 0; c <= 0; d <= 0; e <= 0;
$monitor ("a=%0b b=%0b c=%0b d=%0b e=%0b z=%0b", a, b, c, d, e, z);
for (i = 0; i < 32; i = i + 1) begin
{a, b, c, d, e} = i;
#10;
end
end
endmodule
Salida de simulación (32 combinaciones):
ncsim> run a=0 b=0 c=0 d=0 e=0 z=0 a=0 b=0 c=0 d=0 e=1 z=0 a=0 b=0 c=0 d=1 e=0 z=1 ... a=1 b=1 c=1 d=1 e=1 z=1 ncsim: *W,RNQUIE: Simulation is complete.

assign como always se implementan en la misma lógica hardware.Ejemplo #2: Medio Sumador (Half Adder)
El módulo medio sumador acepta dos entradas escalares a, b y usa lógica combinacional para asignar salidas sum y bit de acarreo cout. La suma es XOR entre a y b, el acarreo es AND entre ambas.
module ha (
input a, b,
output sum, cout
);
assign sum = a ^ b;
assign cout = a & b;
endmodule

Testbench
module tb;
reg a, b;
wire sum, cout;
integer i;
ha u0 ( .a(a), .b(b), .sum(sum), .cout(cout));
initial begin
a <= 0; b <= 0;
$monitor("a=%0b b=%0b sum=%0b cout=%0b", a, b, sum, cout);
for (i = 0; i < 4; i = i + 1) begin
{a, b} = i;
#10;
end
end
endmodule
Salida:
ncsim> run a=0 b=0 sum=0 cout=0 a=0 b=1 sum=1 cout=0 a=1 b=0 sum=1 cout=0 a=1 b=1 sum=0 cout=1 ncsim: *W,RNQUIE: Simulation is complete.

Ejemplo #3: Sumador Completo (Full Adder)
Un sumador completo puede construirse con el medio sumador anterior o aplicar toda la lógica combinacional con assign para impulsar sum y cout.
module fa (
input a, b, cin,
output sum, cout
);
assign sum = (a ^ b) ^ cin;
assign cout = (a & b) | ((a ^ b) & cin);
endmodule

Testbench
module tb;
reg a, b, cin;
wire sum, cout;
integer i;
fa u0 ( .a(a), .b(b), .cin(cin), .sum(sum), .cout(cout));
initial begin
a <= 0; b <= 0;
$monitor("a=%0b b=%0b cin=%0b sum=%0b cout=%0b", a, b, cin, sum, cout);
for (i = 0; i < 8; i = i + 1) begin
{a, b, cin} = i;
#10;
end
end
endmodule
Salida:
ncsim> run a=0 b=0 cin=0 sum=0 cout=0 a=0 b=0 cin=1 sum=1 cout=0 a=0 b=1 cin=0 sum=1 cout=0 a=0 b=1 cin=1 sum=0 cout=1 a=1 b=0 cin=0 sum=1 cout=0 a=1 b=0 cin=1 sum=0 cout=1 a=1 b=1 cin=0 sum=0 cout=1 ncsim: *W,RNQUIE: Simulation is complete.

Ejemplo #4: Multiplexor 2x1
El multiplexor 2x1 usa operador ternario para decidir qué entrada asignar a salida c. Si sel es 1, salida = a; si 0, salida = b.
module mux_2x1 (input a, b, sel, output c);
assign c = sel ? a : b;
endmodule

Testbench
module tb;
reg a, b, sel;
wire c;
integer i;
mux_2x1 u0 ( .a(a), .b(b), .sel(sel), .c(c));
initial begin
a <= 0; b <= 0; sel <= 0;
$monitor("a=%0b b=%0b sel=%0b c=%0b", a, b, sel, c);
for (i = 0; i < 3; i = i + 1) begin
{a, b, sel} = i;
#10;
end
end
endmodule
Salida:
ncsim> run a=0 b=0 sel=0 c=0 a=0 b=0 sel=1 c=0 a=0 b=1 sel=0 c=1 ncsim: *W,RNQUIE: Simulation is complete.

Ejemplo #5: Demultiplexor 1x4
El demultiplexor usa combinación de sel y f para impulsar salidas. Cada salida impulsada por assign separado. No se recomienda impulsar misma señal con diferentes assign.
module demux_1x4 (
input f,
input [1:0] sel,
output a, b, c, d
);
assign a = f & ~sel[1] & ~sel[0];
assign b = f & sel[1] & ~sel[0];
assign c = f & ~sel[1] & sel[0];
assign d = f & sel[1] & sel[0];
endmodule

Testbench
module tb;
reg f;
reg [1:0] sel;
wire a, b, c, d;
integer i;
demux_1x4 u0 ( .f(f), .sel(sel), .a(a), .b(b), .c(c), .d(d));
initial begin
f <= 0; sel <= 0;
$monitor("f=%0b sel=%0b a=%0b b=%0b c=%0b d=%0b", f, sel, a, b, c, d);
for (i = 0; i < 8; i = i + 1) begin
{f, sel} = i;
#10;
end
end
endmodule
Salida:
ncsim> run f=0 sel=0 a=0 b=0 c=0 d=0 f=0 sel=1 a=0 b=0 c=0 d=0 f=0 sel=10 a=0 b=0 c=0 d=0 f=0 sel=11 a=0 b=0 c=0 d=0 f=1 sel=0 a=1 b=0 c=0 d=0 f=1 sel=1 a=0 b=0 c=1 d=0 f=1 sel=10 a=0 b=1 c=0 d=0 f=1 sel=11 a=0 b=0 c=0 d=1 ncsim: *W,RNQUIE: Simulation is complete.

Ejemplo #6: Decodificador 4x16
module dec_3x8 (
input en,
input [3:0] in,
output [15:0] out
);
assign out = en ? 1 << in: 0;
endmodule

Testbench
module tb;
reg en;
reg [3:0] in;
wire [15:0] out;
integer i;
dec_3x8 u0 ( .en(en), .in(in), .out(out));
initial begin
en <= 0; in <= 0;
$monitor("en=%0b in=0x%0h out=0x%0h", en, in, out);
for (i = 0; i < 32; i = i + 1) begin
{en, in} = i;
#10;
end
end
endmodule
Salida:
ncsim> run en=0 in=0x0 out=0x0 ... en=1 in=0x0 out=0x1 en=1 in=0x1 out=0x2 ... en=1 in=0xf out=0x8000 ncsim: *W,RNQUIE: Simulation is complete.

Verilog
- Monitorización precisa de temperatura en armario de servidores con Raspberry Pi
- Circuito con interruptor: guía práctica de circuitos eléctricos básicos
- Circuitos integrados: Fundamentos de puertas lógicas digitales
- Controladores lógicos programables (PLC): control digital moderno para sistemas industriales
- Comprender el álgebra booleana: de fundamentos lógicos a circuitos digitales
- Dominando la Simplificación Lógica con Mapas de Karnaugh
- Dominando Multiplicación y División con Notación Científica
- Industria 4.0: Preguntas y respuestas con Verena Majuntke de Bosch.IO sobre IoT, automatización y la fábrica del futuro
- Dominando VHDL y Verilog: Escribiendo lógica combinacional y secuencial limpia
- Diseño práctico a nivel de puertas en Verilog: Puertas AND, OR, NOT y Multiplexor 2x1
- Dominar $timeformat en Verilog: Control de precisión y visualización