The verilog assign statement is typically used to continuously drive a signal of wire datatype and gets synthesized as combinational logic. Here are some more design examples using the assign statement.

Example #1 : Simple combinational logic

The code shown below implements a simple digital combinational logic which has an output wire z that is driven continuously with an assign statement to realize the digital equation.


module combo ( 	input 	a, b, c, d, e,
								output 	z);

	assign z = ((a & b) | (c ^ d) & ~e);
	
endmodule

The module combo gets elaborated into the following hardware schematic using synthesis tools and can be seen that the combinational logic is implemented with digital gates.

simple combinational logic with assign

Testbench

The testbench is a platform for simulating the design to ensure that the design does behave as expected. All combinations of inputs are driven to the design module using a for loop with a delay statement of 10 time units so that the new value is applied to the inputs after some time.


module tb;
	// Declare testbench variables
  reg a, b, c, d, e;
  wire z;
  integer i;
  
  // Instantiate the design and connect design inputs/outputs with
  // testbench variables
  combo u0 ( .a(a), .b(b), .c(c), .d(d), .e(e), .z(z));
  
  initial begin
  	// At the beginning of time, initialize all inputs of the design
  	// to a known value, in this case we have chosen it to be 0.
    a <= 0;
    b <= 0;
    c <= 0;
    d <= 0;
    e <= 0;
    
    // Use a $monitor task to print any change in the signal to 
    // simulation console 
    $monitor ("a=%0b b=%0b c=%0b d=%0b e=%0b z=%0b", 
              a, b, c, d, e, z);
    
    // Because there are 5 inputs, there can be 32 different input combinations
    // So use an iterator "i" to increment from 0 to 32 and assign the value
    // to testbench variables so that it drives the design inputs
    for (i = 0; i < 32; i = i + 1) begin
      {a, b, c, d, e} = i;
      #10;
    end
  end
endmodule
 Simulation Log
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=0 b=0 c=0 d=1 e=1 z=0
a=0 b=0 c=1 d=0 e=0 z=1
a=0 b=0 c=1 d=0 e=1 z=0
a=0 b=0 c=1 d=1 e=0 z=0
a=0 b=0 c=1 d=1 e=1 z=0
a=0 b=1 c=0 d=0 e=0 z=0
a=0 b=1 c=0 d=0 e=1 z=0
a=0 b=1 c=0 d=1 e=0 z=1
a=0 b=1 c=0 d=1 e=1 z=0
a=0 b=1 c=1 d=0 e=0 z=1
a=0 b=1 c=1 d=0 e=1 z=0
a=0 b=1 c=1 d=1 e=0 z=0
a=0 b=1 c=1 d=1 e=1 z=0
a=1 b=0 c=0 d=0 e=0 z=0
a=1 b=0 c=0 d=0 e=1 z=0
a=1 b=0 c=0 d=1 e=0 z=1
a=1 b=0 c=0 d=1 e=1 z=0
a=1 b=0 c=1 d=0 e=0 z=1
a=1 b=0 c=1 d=0 e=1 z=0
a=1 b=0 c=1 d=1 e=0 z=0
a=1 b=0 c=1 d=1 e=1 z=0
a=1 b=1 c=0 d=0 e=0 z=1
a=1 b=1 c=0 d=0 e=1 z=1
a=1 b=1 c=0 d=1 e=0 z=1
a=1 b=1 c=0 d=1 e=1 z=1
a=1 b=1 c=1 d=0 e=0 z=1
a=1 b=1 c=1 d=0 e=1 z=1
a=1 b=1 c=1 d=1 e=0 z=1
a=1 b=1 c=1 d=1 e=1 z=1
ncsim: *W,RNQUIE: Simulation is complete.

Example #2: Half Adder

The half adder module accepts two scalar inputs a and b and uses combinational logic to assign the outputs sum and carry bit cout . The sum is driven by an XOR between a and b while the carry bit is obtained by an AND between the two inputs.


module ha ( input 	a, b,
						output	sum, cout);

	assign sum  = a ^ b;
	assign cout = a & b;
endmodule
half adder circuit with assign

Testbench


module tb;
	// Declare testbench variables
  reg a, b;
  wire sum, cout;
  integer i;

  // Instantiate the design and connect design inputs/outputs with
  // testbench variables  
  ha u0 ( .a(a), .b(b), .sum(sum), .cout(cout));
  
  initial begin
  	// At the beginning of time, initialize all inputs of the design
  	// to a known value, in this case we have chosen it to be 0.  
    a <= 0;
    b <= 0;
    
    // Use a $monitor task to print any change in the signal to 
    // simulation console     
    $monitor("a=%0b b=%0b sum=%0b cout=%0b", a, b, sum, cout);
    
    // Because there are only 2 inputs, there can be 4 different input combinations
    // So use an iterator "i" to increment from 0 to 4 and assign the value
    // to testbench variables so that it drives the design inputs    
    for (i = 0; i < 4; i = i + 1) begin
      {a, b} = i;
      #10;
    end
  end
endmodule
 Simulation Log
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.

Example #3: Full Adder

A full adder can be built using the half adder module shown above or the entire combinational logic can be applied as is with assign statements to drive the outputs sum and cout .


module fa (	input 	a, b, cin,
						output 	sum, cout);

	assign sum  = (a ^ b) ^ cin;
	assign cout = (a & b) | ((a ^ b) & cin);
endmodule
full adder circuit with assign

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 < 7; i = i + 1) begin
      {a, b, cin} = i;
      #10;
    end
  end
endmodule
 Simulation Log
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.

Example #4: 2x1 Multiplexer

The simple 2x1 multiplexer uses a ternary operator to decide which input should be assigned to the output c . If sel is 1, output is driven by a and if sel is 0 output is driven by b .


module mux_2x1 (input 	a, b, sel,
								output 	c);
				
	assign c = sel ? a : b;
endmodule
2x1 multiplexer

Testbench


module tb;
	// Declare testbench variables
  reg a, b, sel;
  wire c;
  integer i;
  
  // Instantiate the design and connect design inputs/outputs with
  // testbench variables  
  mux_2x1 u0 ( .a(a), .b(b), .sel(sel), .c(c));
  
  initial begin
  	// At the beginning of time, initialize all inputs of the design
  	// to a known value, in this case we have chosen it to be 0.    
    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
 Simulation Log
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.

Example #5: 1x4 Demultiplexer

The demultiplexer uses a combination of sel and f inputs to drive the different output signals. Each output signal is driven by a separate assign statement. Note that the same signal is generally not recommended to be driven by different assign statements.


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
1x4 demultiplexer

Testbench


module tb;
	// Declare testbench variables
  reg f;
  reg [1:0] sel;
  wire a, b, c, d;
  integer i;
  
  // Instantiate the design and connect design inputs/outputs with
  // testbench variables  
  demux_1x4 u0 ( .f(f), .sel(sel), .a(a), .b(b), .c(c), .d(d));
  
  // At the beginning of time, initialize all inputs of the design
  // to a known value, in this case we have chosen it to be 0.  
  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);
    
    // Because there are 3 inputs, there can be 8 different input combinations
    // So use an iterator "i" to increment from 0 to 8 and assign the value
    // to testbench variables so that it drives the design inputs    
    for (i = 0; i < 8; i = i + 1) begin
      {f, sel} = i;
      #10;
    end
  end
endmodule
 Simulation Log
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.

Example #6: 4x16 Decoder


module dec_3x8 ( 	input 					en,
									input 	[3:0] 	in,
									output  [15:0] 	out);

	assign out = en ? 1 << in: 0;
endmodule
4x16 decoder

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
 Simulation Log
ncsim> run
en=0 in=0x0 out=0x0
en=0 in=0x1 out=0x0
en=0 in=0x2 out=0x0
en=0 in=0x3 out=0x0
en=0 in=0x4 out=0x0
en=0 in=0x5 out=0x0
en=0 in=0x6 out=0x0
en=0 in=0x7 out=0x0
en=0 in=0x8 out=0x0
en=0 in=0x9 out=0x0
en=0 in=0xa out=0x0
en=0 in=0xb out=0x0
en=0 in=0xc out=0x0
en=0 in=0xd out=0x0
en=0 in=0xe out=0x0
en=0 in=0xf out=0x0
en=1 in=0x0 out=0x1
en=1 in=0x1 out=0x2
en=1 in=0x2 out=0x4
en=1 in=0x3 out=0x8
en=1 in=0x4 out=0x10
en=1 in=0x5 out=0x20
en=1 in=0x6 out=0x40
en=1 in=0x7 out=0x80
en=1 in=0x8 out=0x100
en=1 in=0x9 out=0x200
en=1 in=0xa out=0x400
en=1 in=0xb out=0x800
en=1 in=0xc out=0x1000
en=1 in=0xd out=0x2000
en=1 in=0xe out=0x4000
en=1 in=0xf out=0x8000
ncsim: *W,RNQUIE: Simulation is complete.