Verilog case statement in Combinatorial circuit

 case statement

When the number of the nesting grows, it becomes difficult to understand the if else statement. The verilog case statement, comes handy in such cases. We will first look at the usage of the case statement and then learn about its syntax and variations.

We had earlier written a simple multiplexer. A multiplexer selects one of several input signals and forwards the selected input to a single output line.
A single bit multiplexer will have one control line two inputs ( say X and Y) and one output ( say Z). When the control is 0, X is connected to Z. When the Control is 1, Y is connected to Z.
The figure below explains this Let write this example using verilog case statement
 // www.referencedesigner.com // Verilog Tutorial // Example of multiplexer module mux_case(out,cntrl,in1,in2);input cntrl,in1,in2;output out;reg out; always @ *case (cntrl)1'b0: out = in1;1'b1 :out = in2;endcaseendmodule

Note that we had to assign out as a register in

reg out;

This is because we need to assign values to it explicitly and not drive them. This is called procedural assignment. We can not assign a wire data type explicitly. The previous example we had done using a continuous assignment statement. The case statement

out = in1;

Could have a begin and end as in

begin
out = in1;
end

In our case, it was not required because we had only one statement. We now suggest that you write a test bench for this code and verify that it works. If you have difficulty, you can check it with following test bench

 module stimulus;wire out;reg cntrl,in1,in2;mux_case uut(out,cntrl,in1,in2);initialbegin \$monitor(\$time," out=%b,cntrl=%b,in1=%b,in2=%b",out,cntrl,in1,in2); cntrl=0;in1=0;in2=0; #1 in1=1;in2=0; #1 in1=0;in2=1; #1 in1=1; in2=1; #1 cntrl=1; #1 in1=0;in2=0; #1 in1=1;in2=0; #1 in1=0;in2=1; #1 in1=1; in2=1; #10 \$finish;endendmodule

case  [case-expr}
[item]  :
begin
[procedural statementl  ;
[procedural statementl  ;
. .  .
end
[item]  :
begin
[procedural statement  1  ;
[procedural statement  1  ;
.  . .
end
[iteml  :
begin
[procedural statement  1  ;
[procedural statementl;
end
. . .
default:
begin
[procedural statement  1  ;
[procedural statementl;
end
endcase

Let us now take a look at another example. This time we will rewrite the priority encoder example we presented in the previous section using the case statement. Recall the table for a 4 input priority encoder

Table: A priority encoder with 4 Inputs

 x x x x Output z 1 - - - 100 0 1 - - 011 0 0 1 - 010 0 0 0 1 001 0 0 0 0 1

When the x input is 1, it has highest priority and irrespective of the values of other bits, we will give the output that corresponds to the binary digit corresponding to 4 in x or 100. Similarly, if the x is zero and the priority of the next bit x is high, then irrespective of the values of x and x, we give output corresponding to 3 of x - or 011. We follow the same logic as per the table above.

Let us now write the actual verilog code that implement the priority encoder using case statements

 // Referencedesigner.com // Priority Encoder Example - Usage of case// Verilog Tutorial  module priory_encoder_case(input wire [4:1] x,output reg [2:0] pcode );always @ * case (x)4'b1000, 4'b1001 , 4'b1010, 4'b1011 , 4'b1100 , 4'b1101, 4'b1110 , 4'b1111 :pcode = 3'b100;4'b0100, 4'b0101 , 4'b0110, 4'b0111 :pcode = 3'b011 ;4'b0010, 4'b0011 :pcode = 3'b010;4'b0001 :pcode = 3'b001;4'b0000 : pcode = 3'b000;endcase endmodule

Note that the always statement always @(x, x,x, x) Could be written as always @ * We now suggest that you write a test bench for this code and verify that it works. If you have sifficulty, you can check it with following test bench

 `timescale 1ns / 1psmodule stimulus; reg [4:1] x; wire [2:0] pcode; // Instantiate the Unit Under Test (UUT) priory_encoder_case uut ( .x(x), .pcode(pcode) );  initial begin // Initialize Inputsx = 4'b0000;   #20 x = 4'b0001; #20 x = 4'b0010; #20 x = 4'b0011; #20 x = 4'b0100; #20 x = 4'b0101; #20 x = 4'b0110; #20 x = 4'b0111; #20 x = 4'b1000; #20 x = 4'b1001; #20 x = 4'b1010; #20 x = 4'b1011; #20 x = 4'b1100; #20 x = 4'b1101; #20 x = 4'b1110; #20 x = 4'b1111; #40 ;  end   initial begin \$monitor("t=%3d x=%4b,pcode=%3b",\$time,x,pcode ); end endmodule

Notice the use of the case statement
4'b1000, 4'b1001 , 4'b1010, 4'b1011 , 4'b1100 , 4'b1101, 4'b1110 , 4'b1111 :
pcode  = 3'b100;

When the vale of x matches any of the following values
4'b1000, 4'b1001 , 4'b1010, 4'b1011 , 4'b1100 , 4'b1101, 4'b1110 , 4'b1111 :
The statement next to it
pcode  = 3'b100;
is executed. Notice that this could also be have been written as
4'b1000, 4'b1001 , 4'b1010, 4'b1011 , 4'b1100 , 4'b1101, 4'b1110 , 4'b1111 :
begin
pcode  = 3'b100;
end

The boolean-expr is evaluated and if it is true, the list of the procedural statements between begin and end is executed. If the boolean-expr is false the procedural statements in the else block is executed. The begin and end can be omitted if there is only one procedural statement as in the case of our example. The else statement can become else statement if we wish to check second condition.

A Binary Decoder Example

We will now present another example that will make use of if statement. A Binary decoder is a circuit that has n inputs and 2n outputs. It asserts one and only one 2n outputs depending upon the input.

Let us say our binary decoder has 2 inputs x and x and 4 outputs y, y, y, y.

We are also making the decoder circuit a bit more complicated by requiring an enable signal. If the enable is 0 ( means it is disabled), the output will be 4'b0000.

The table below shows the function of the Binary decoder.

Table: A 2 to 4 binary Decoder with Enable Signal

 Enable x x Output y[3:0] 0 - - 0000 1 0 0 0001 1 0 1 0010 1 1 0 0100 1 1 1 1000

Can you now try to implement the above on your own without looking at the code presented below.
 // Referencedesigner.com // Binary Decoder Example - Usage of if// Verilog Tutorial  module binary_encoder(input wire [1:0] x,input wire enable,output reg [3:0] y ); always @(enable, x,x) if (enable == 1'b0) y=4'b0000;else if (x == 2'b00) y = 4'b0001;else if (x == 2'b01) y = 4'b0010;else if (x == 2'b10) y = 4'b0100;else if (x == 2'b11) y = 4'b1000; endmodule

Note that the if statement

if (enable == 1'b0)

Could also be written as

if (~enable)

We now suggest that you write a test bench for this code and verify that it works. If you have sifficulty, you can check it with following test bench

 `timescale 1ns / 1psmodule stimulus; reg [1:0] x; reg enable; wire [3:0] y; // Instantiate the Unit Under Test (UUT) binary_encoder uut ( .x(x), .enable(enable), .y(y) );  initial begin // Initialize Inputsx = 4'b0000; enable = 0;   #20 enable = 1; #20 x = 2'b01; #20 x = 2'b10; #20 x = 2'b11; #40 ;  end   initial begin \$monitor("t=%3d enable=%1b,x=%2b, y=%4b",\$time,enable,x,y ); end endmodule

 Exercise

1. Run the Multiplexer example, but at this time we should have 2 control bits, 4 input pins and 1 output pin. One of the 4 inputs will be connected to the output depending upon the control bit. Check the solution here