2012年10月11日 星期四

Different ways to code Verilog: A Multiplexer example

Verilog Design: Harsha Perla 
Different ways to code Verilog: A Multiplexer example
        There are different ways to design a circuit in Verilog. In this tutorial I have used seven different ways to implement a 4 to 1 MUX. After synthesizing, five of them gave same RTL level circuit in Xilinx Project navigator. Let us start with a block diagram of multiplexer.
 
Example I
              If select is 0, output q will be d[0]; if select is 1, q will be d[1]; if select is 2, q will be d[2] and if select is 3, q will be d[3]. This logic can be implemented using Verilog code as follows:
// Verilog code for Multiplexer implementation using assign// File name: mux1.v 
// by Harsha Perla for http://electrosofts.com

// harsha@electrosofts.com

// Available at http://electrosofts.com/verilog

module mux1( select, d, q );

input[1:0] select;
input[3:0] d;
output     q;

wire      q;
wire[1:0] select;
wire[3:0] d;

assign q = d[select];

endmodule
Click here to download all examples
         declaration  'input[1:0] select;' specifies select as port of 2 bits, with MSB select[1] and LSB select[0]. All the ports are declared as arrays because all the input signals must be declared as wires and left side of continuous statements should be wire. Actually, ports are wire by default and we need not declare it. But it is better to declare for our convenience.
         When select is 00, q will be assigned d[0], when select is 01, q will be assigned d[1] and so on. To test this, use following testbench. It generates a truth table with all possible values in the input and select.
// Verilog testbench for 4 to 1 Multiplexer
// by Harsha Perla for http://electrosofts.com
// Comments to: harsha@electrosofts.com 
// Available at http://electrosofts.com/verilog

module mux_tb;

reg[3:0] d;
reg[1:0] select;
wire     q;

integer  i;

mux1 my_mux( select, d, q );

initial
begin
   #1 $monitor("d = %b", d, "  |  select = ", select, "  |  q = ", q );

   for( i = 0; i <= 15; i = i + 1)
   begin
      d = i;
      select = 0;  #1;
      select = 1;  #1;
      select = 2;  #1;
      select = 3;  #1;
      $display("-----------------------------------------");
    end

end
endmodule
          $monitor keeps displaying the values of its arguments whenever one of that changes. i.e., whenever values of d, select or q changes, it displays the value in the output window. Using a for loop, I have changed value of d from 0000 to 1111, and in each case change the value of select to all possible values. A part of output is as displayed the diagram in the right.
             Note that if we use  for( d = 0; d <= 15; d = d + 1) instead of  
for
( i = 0; i <= 15; i = i + 1), for loop will go to infinite loop since d can never be greater that 15; so the condition d <= 15 will always be true.
             Wave output of the above code taken from the ModelSim simulation is shown bellow.
            You can use same test bench for all the multiplexer codes here.  This output and wave diagrams are same for all the codes.


Example II
       This example is very similar to previous one, but instead of using continuous assignments, here alwaysstatement is used. left side of expressions inside an always block must be of register type. So, here q is declared s reg. When ever d or select changes, q should be changed to d[select]. So, d and select are added to the 'sensitivity list'. Even though we declared q is reg here, hardware register won't be used by synthesis tool to implement q. This is because always block here is combinational. Remember that if sensitivity list contains right hand side signals in the expressions and blocking statements are used, it will be combinational circuit when synthesising.

// Verilog code for Multiplexer implementation using always block.
// by Harsha Perla for http://electrosofts.com
// harsha@electrosofts.com 
// Available at http://electrosofts.com/verilog

module mux2( select, d, q );

input[1:0] select;
input[3:0] d;
output     q;

reg        q;
wire[1:0]  select;
wire[3:0]  d;

always @(d or select)
    q = d[select];

endmodule
            Use the same testbench as previous one for this code. Change mux1 my_mux by mux2 my_mux.
Example III
             This example uses if statement of Verilog. Here also q is declared as reg and other signals as wire. This example also uses always block with the same sensitivity list. You can understand this code very easily.
// Verilog code for Multiplexer implementation using if statement.
// by Harsha Perla for http://electrosofts.com
// harsha@electrosofts.com 
// Available at http://electrosofts.com/verilog

module mux3( select, d, q );

input[1:0] select;
input[3:0] d;
output q;

reg q;
wire[1:0] select;
wire[3:0] d;

always @( select or d )
begin
   if( select == 0)
      q = d[0];

   if( select == 1)
      q = d[1];

   if( select == 2)
      q = d[2];

   if( select == 3)
      q = d[3];
end

endmodule
           Actually this example (next one also) has more code to write. But if select and input signals are having separate name instead of packed arrays like d1, d2, select1. This code is more easy to understand and very useful if inputs are coming from different sources.
Example IV
           Next example is also similar one. Here, case statement is used. case statement switches the execution of the code to corresponding block depending on the value of the parameter passed.
// Verilog code for Multiplexer implementation using case statement.
// by Harsha Perla for http://electrosofts.com
// harsha@electrosofts.com 
// Available at http://electrosofts.com/verilog

module mux4( select, d, q );

input[1:0] select;
input[3:0] d;
output     q;

reg       q;
wire[1:0] select;
wire[3:0] d;

always @( select or d )
begin
   case( select )
       0 : q = d[0];
       1 : q = d[1];
       2 : q = d[2];
       3 : q = d[3];
   endcase
end

endmodule
Example V
          This example uses nested conditional statement. Meaning of the assign statement in the following code is "If select = 0, q = d[0], else if select is 1 q = d[1]. else if select is 2 q = d[2], else q = d[3]. We can use conditional statement inside always block also.
// Verilog code for Multiplexer implementation using conditional statement.
// by Harsha Perla for http://electrosofts.com
// harsha@electrosofts.com 
// Available at http://electrosofts.com/verilog

module mux5( select, d, q );

input[1:0] select;
input[3:0] d;
output q;

wire q;
wire[1:0] select;
wire[3:0] d;

assign q = ( select == 0 )? d[0] : ( select == 1 )? d[1] : ( select == 2 )? d[2] : d[3];

endmodule
       All the examples till now uses behavioral style of coding. Next example is data flow style of code.
Example VI
        If we write an expression for 4 to 1 multiplexer, we can convert the expression in to code. Consider the expression bellow:
q = ( select[0].select[1].d[0] ) + ( select[0].select[1].d[1] ) + ( select[0].select[1].d[2] ) + ( select[0].select[1].d[3] )
         You can write a truth table to verify the equation. Now we can write a code using Verilog for this equation as follows. We can also use assign statement instead of writing always block.

// Verilog code for Multiplexer implementation in dataflow level.
// by Harsha Perla for http://electrosofts.com
// harsha@electrosofts.com 
// Available at http://electrosofts.com/verilog

module mux6( select, d, q );

input[1:0] select;
input[3:0] d;
output q;

reg q;
wire[1:0] select;
wire[3:0] d;

always @( select or d)
begin
    q =       ( ~select[0] & ~select[1] & d[0] )
            | (  select[0] & ~select[1] & d[1] )
            | ( ~select[0] &  select[1] & d[2] )
            | (  select[0] &  select[1] & d[3] );
end

endmodule
Example VII
This example is gate level implementation of the multiplexer. All basic gates are declared in Verilog. We can instantiate them to get a gate level circuit. Let us draw the diagram of multiplexer first.
           Now, convert the circuit in to code. instantiate 2 NOT gates, four AND gates and one OR gate as in the diagram. All the outputs from the gates should be wire. Hence code contains all the signals as wires.

// Verilog code for Mux implementation using instantiating gates.
// by Harsha Perla for http://electrosofts.com
// harsha@electrosofts.com 
// Available at http://electrosofts.com/verilog

module mux7( select, d, q );

input[1:0] select;
input[3:0] d;
output     q;

wire       q, q1, q2, q3, q4, NOTselect0, NOTselect1;
wire[1:0]  select;
wire[3:0]  d;

not n1( NOTselect0, select[0] );
not n2( NOTselect1, select[1] );

and a1( q1, NOTselect0, NOTselect1, d[0]  );
and a2( q2,  select[0], NOTselect1, d[1]  );
and a3( q3, NOTselect0,  select[1], d[2]  );
and a4( q4,  select[0],  select[1], d[3]  );

or o1( q, q1, q2, q3, q4 );

endmodule
Click here to to download all the examples
More tutorials on Verilog is to be added soon.

沒有留言:

張貼留言

2024_09 作業3 以Node-Red 為主

 2024_09 作業3  (以Node-Red 為主  Arduino 可能需要配合修改 ) Arduino 可能需要修改的部分 1)mqtt broker  2) 主題Topic (發行 接收) 3) WIFI ssid , password const char br...