View Course Path

Verilog code for 4:1 Multiplexer (MUX) – All modeling styles

After reading this post, you’ll be able to:

  1. Write the Verilog code for a 4:1 MUX in all layers of abstraction (modeling styles)
  2. Generate the RTL schematic for the 4:1 MUX and simulate the design code using testbench.

What is a multiplexer?

A multiplexer is a data selector device that selects one input from several input lines, depending upon the enabled, select lines, and yields one single output.

A multiplexer of 2n inputs has n select lines, are used to select which input line to send to the output. There is only one output in the multiplexer, no matter what’s its configuration.

These devices are used extensively in the areas where the multiple data can be transferred over a single line like in the communication systems and bus architecture hardware. Visit this post for a crystal clear explanation to multiplexers.

We’ll code the 4:1 multiplexer in the following abstraction layers:

  1. Gate level modeling
  2. Dataflow modeling
  3. Behavioral modeling
  4. Structural modeling

A brief description for each modeling level has been presented before we start coding the HDL models in Verilog HDL.

Gate level modeling

The gate-level abstraction is the lowest level of modeling. The switch level model is also a low level of modeling but it isn’t that common. The gate-level modeling style uses the built-in basic logic gates predefined in Verilog. We only need to know the logic diagram of the system since the only requirement is to know the layout of the particular logic gates.

Logic circuit

LOGIC DIAGRAM 4X1 MUX
Logic diagram 4×1 multiplexer

Now, this circuit shows we need two NOT gates, four AND gates, and one OR gate for implementing the 4×1 MUX in gate-level modeling.

Verilog code for 4×1 multiplexer using gate-level modeling

To start with the design code, as expected, we’ll declare the module first. The port-list will contain the output variable first in gate-level modeling. This is because the built-in logic gates are designed such that the output is written first, followed by the other input variables or signals.

module m41(out, a, b, c, d, s0, s1);

Now since the nature or behavior of the circuit in the gate – level isn’t concerned, there is no need to define the data type of variable.

output out; 
input a, b, c, d, s0, s1;

The intermediate signals are declared as wires. Note that the intermediate signals are those that are not involved in the port list. Example: signals that are emerging from the NOT gate.

wire sobar, s1bar, T1, T2, T3, T4;

Time for us to write for the logic gates. Separate the list for a particular gate by appropriate brackets, if there exists more than one same logic gate. Here’s how you would do it for the two NOT gates.

not (s0bar, s0), (s1bar, s1);

Here s0bar and s1bar are the output to the first and second NOT gate respectively and s0 and s1 are the input to the first and second NOT gate.

Similarly for the rest of the two gates;

and (T1, a, s0bar, s1bar), (T2, b, s0bar, s1), (T3, c, s0, s1bar), (T4, d, s0, s1);
or(out, T1, T2, T3, T4);

So the final code is:

module m41(out, a, b, c, d, s0, s1);

output out;
input a, b, c, d, s0, s1;
wire sobar, s1bar, T1, T2, T3, T4;

not (s0bar, s0), (s1bar, s1);
and (T1, a, s0bar, s1bar), (T2, b, s0bar, s1),(T3, c, s0, s1bar), (T4, d, s0, s1);
or(out, T1, T2, T3, T4);

endmodule

RTL Schematic

This hardware schematic is the RTL design of the circuit. Notice the resemblance between the logic circuit of 4:1 MUX and this picture. It is clear that the gate-level modeling will give the exact involved hardware in the circuit of the system.

RTL SCHEMATIC GATE-LEVEL MODELING
RTL schematic Gate-level modeling

Data flow modeling

The dataflow modeling represents the flow of the data. It is described through the data flow through the combinational circuits rather than the logic gates used.

In Verilog, the assign statement is used in data-flow abstraction.

It is necessary to know the logical expression of the circuit to make a dataflow model. The equation for 4:1 MUX is:

Logical Expression:  out = (a. s1′.s0′) + (b.s1′.s0) + (c.s1.s0′) + (d. s1.s0)

Verilog code for 4×1 multiplexer using data flow modeling

Start with the module and input-output declaration. m41 is the name of the module.

module m41 ( input a,  
input b,  
input c,  
input d,  
input s0, s1, 
output out);

Using the assign statement to express the logical expression of the circuit. A ternary operator ? is used here to implement the logic. This operator works similar to that of C programming language.

 assign out = s1 ? (s0 ? d : c) : (s0 ? b : a);

This shows that if s1 is high, the (s0 ? d : c) block will be executed, else (s0 ? b : a) will be executed. Further, if s0 is high, d OR b will get transferred to the out variable, depending on the s1 select line, else c OR a will be the output.

Thus, the final code for the 4:1 multiplexer using data-flow modeling is given below.

module m41 ( input a, 
input b, 
input c, 
input d, 
input s0, s1,
output out); 

 assign out = s1 ? (s0 ? d : c) : (s0 ? b : a); 

endmodule

RTL Schematic

You can observe how the RTL of 4:1 MUX in dataflow is different from the gate-level modeling. The figure consists of two individual 2:1 multiplexers, connected by the two select lines s0 and s1.

RTL SCHEMATIC DATAFLOW MODELING
RTL schematic dataflow modeling

Behavioral modeling

The behavioral style, as the name suggests, describes the behavior of a circuit. It is the highest abstraction layer in the Verilog modeling of digital systems.  The other techniques are detailed with their internal hardware whereas the behavioral level doesn’t demand the knowledge of the actual circuitry involved in the system.

Truth table

The truth table of the 4:1 MUX has six input variables, out of which two are select lines, and one is the output signal. The input data lines a, b, c, d are selected depending on the values of the select lines.

TRUTH TABLE 4X1 MUX
Truth table of 4×1 Mux

Verilog code for 4×1 multiplexer using behavioral modeling

To start with the behavioral style of coding, we first need to declare the name of the module and its port associativity list, which will further contain the input and output variables. Point to be noted here; we are supposed to define the data- type of the declared variable also since it will account for the behavior of the input and output signals.

s0 s1 select lines will be vector quantities, and vector net entities are declared as wire. The output variable out is reg.

module m41 ( a, b, c, d, s0, s1, out);
input wire a, b, c, d;
input wire s0, s1;
output reg out;

Next comes the initial and always. In behavioral modeling, there are two main statements responsible for the construct of Verilog.

One is the initial statement, which is executed only once during the simulation; another one is the always statement that can be executed every time its sensitivity list gets triggered.

If you carefully look at the equation, the output is explicitly dependent on the input variables. To implement this, we’ll use the always statement, followed by begin...end block.

always @ (a or b or c or d or s0 or s1)
begin
...
end

In most of the cases, the input variables are present in the sensitivity list. Another way of expressing this list is by using the asterisk symbol *.

always @(*)

This implicitly expresses the event expression/sensitivity list. It is always convenient to eliminate the source errors with the always @ (*). This method will let the program decide what to include in the sensitivity list.

Next, to describe the behavior of 4×1 MUX, look at the following line statements:

  • When s0 s1 are both high, input d is the output
  • s0 low s1 high, input c is the output
  • When s0 high s1 low, input b is the output
  • Otherwise, s0 s1 are both low, input a is the output.

To implement this, we can either use the if-else statement or the case statement. I am using the case statement over here.

The case statement starts with the case keyword and ends with the endcase. The syntax for the case statement is:

case (case_expression)
      case_item1: procedural_expression;   
      case_item2: begin
                    procedural_statements;    
                  end        
      ....   
      default: expression;
endcase

The expression for case_expression is the OR (symbol |) operation between select lines. Analyze the truth table and write down the case statement for the first row.

2'b00 : out <= a;

The above line shows that when select line s0 and s1 is 00, a input is transferred to the output out. Repeat this for the rest of the rows of cases.

The final code for 4×1 MUX in behavioral modeling is as follows:

module m41 ( a, b, c, d, s0, s1, out);

input wire a, b, c, d;
input wire s0, s1;
output reg out;

always @ (a or b or c or d or s0, s1)
begin

case (s0 | s1)
2'b00 : out <= a;
2'b01 : out <= b;
2'b10 : out <= c;
2'b11 : out <= d;
endcase

end

endmodule

RTL Schematic

This hardware schematic is the actual schematic of a multiplexer.

RTL SCHEMATIC BEHAVIORAL MODELING
RTL schematic behavioral modeling

Structural modeling

In structural modeling, we describe the physical structure of a digital system. It is implemented using the logic gates in the circuit diagram. It gives us the internal hardware involved in the system.

There’s one thing that should be noted over here. Gate-level modeling is different from structural level modeling. In gate-level, we use the predefined built-in logical gates. In contrast, in structural-level, we create a separate module for each functional logic gate with its logical expression assigned to that module.

Logic circuit

LOGIC CIRCUIT

This circuit has four AND gates, two NOT gates and one OR gate. We’ll structurize each gate with its respective module.

Verilog code for 4×1 multiplexer using structural modeling

To start with the design code, we’ll first define the modules for AND, OR, and NOT gates.

The declaration of the AND gate is shown below. The name of the module is and_gate. The input and output can be defined either along the port-list or separately in the next line. There is no need to specify the data-type of the signals since we are coding in the structural style.

module and_gate(output a, input b, c, d);

Using the assign statement, write down the logical expression for AND gate.

assign a = b & c & d;

The end of the module is marked by endmodule keyword.

endmodule

Repeat the above for the rest of the gates=>

NOT gate:=

module not_gate(output f, input e); 
assign e = ~ f; 
endmodule

OR gate:=

module or_gate(output l, input m, n, o, p); 
assign l = m | n | o | p; 
endmodule

You may notice the names of the input and output variables are different from each of the modules. This ensures no mixing up of signals during the simulation of the circuit.

Time for us to combine these three gates to form a 4:1 MUX. This is called the module instantiation. First, start with the name of the module (defined and declared above) and write the name of the instance of your choice. The port-list will contain the output signals, followed by the input ones.

and_gate u3(T1, a, s0bar, s1bar);
  • Here, the module used: and_gate
  • Name of the instance: u3
  • Output variable: T1 (which is an intermediate signal defined as a wire)
  • Input variable: a, s0bar, s1bar

Repeat the same for the rest of the instances.

not_gate u1(s1bar, s1); 
not_gate u2(s0bar, s0); 
and_gate u3(T1, a, s0bar, s1bar); 
and_gate u4(T2, b, s0, s1bar); 
and_gate u5(T3, c, s0bar, s1); 
and_gate u6(T4, d, s0, s1); 
or_gate u7(out, T1, T2, T3, T4);

Final structural code:

module and_gate(output a, input b, c, d);
assign a = b & c & d;
endmodule

module not_gate(output f, input e);
assign e = ~ f;
endmodule

module or_gate(output l, input m, n, o, p);
assign l = m | n | o | p;
endmodule

module m41(out, a, b, c, d, s0, s1);
output out;
input a, b, c, d, s0, s1;
wire s0bar, s1bar, T1, T2, T3;
not_gate u1(s1bar, s1);
not_gate u2(s0bar, s0);
and_gate u3(T1, a, s0bar, s1bar);
and_gate u4(T2, b, s0, s1bar);
and_gate u5(T3, c, s0bar, s1);
and_gate u6(T4, d, s0, s1);
or_gate u7(out, T1, T2, T3, T4);
endmodule

RTL Schematic

You can see each instantiate represents a particular functionality, comprising different logic gates.

RTL SCHEMATIC STRUCTURAL MODELING
RTL schematic structural modeling

Testbench for 4×1 mux using Verilog

A testbench is an HDL code that allows you to provide a set of stimuli input to test the functionality and wide-range of plausible inputs for support to a system. Check out this post to learn how to write the testbench via our step-by-step instructions.

The name of the module: top

Output variable: out

Input variables: a, b, c, d

Select lines: s0, s1

Name of the module instance: name

module top;

wire  out;
reg  a;
reg  b;
reg  c;
reg  d;
reg s0, s1;

m41 name(.out(out), .a(a), .b(b), .c(c), .d(d), .s0(s0), .s1(s1));
 initial
 begin

 a=1'b0; b=1'b0; c=1'b0; d=1'b0;
 s0=1'b0; s1=1'b0;
 #500 $finish;

end

always #40 a=~a;
always #20 b=~b;
always #10 c=~c;
always #5 d=~d;
always #80 s0=~s0;
always #160 s1=~s1;

always@(a or b or c or d or s0 or s1) 
$monitor("At time = %t, Output = %d", $time, out);

endmodule;

Simulation Waveforms

The following window is the simulation log for the 4:1 multiplexer. The waveforms remain the same for all the styles of modeling.
Simulation Waveform 4x1 MUX
Simulation Waveform 4×1 MUX

5 thoughts on “Verilog code for 4:1 Multiplexer (MUX) – All modeling styles

  1. in gate level modelling , while declaring s0bar as wire , you have written ‘so’ instead of ‘s0’.
    please correct.

    thanks

  2. Check the functionality of behavioral modelling.
    when s0=0 and s1=0 : a will be connected as input
    when s0=0 and s1=1: b will be connected as input
    when s0=1 and s1=0: again b will be connected as input
    when s0=1 and s1=1: again a will be connected as input

    that means c and d will never be used.
    And the schematic diagram is also wrong.

  3. this is wrong. when s0 and s1 are high a 4:1 multiplex should output the value stored in d. it is evident after testing your code and viewing your graph that it wrongly outputs the value stored in b instead.

  4. Hello,

    For the test bench, what is the reason for each of the “always #40 a=~a;”? What does always do, why do you make the input equal to the negated input, and why does each have a different times like #40, #5, #10, etc?

    Also in the test bench, what is “always@(a or b or c or d or s0 or s1)” for?

  5. In gate-level modeling
    1. Why is the “wire sobar, s1bar, T1, T2, T3, T4;” not declared as an output?
    2. In line “and (T1, a, s0bar, s1bar)” how does the software know that s0bar & s1bar is an input?abhice

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.