The Conditional Statement - amirrezatav/Verilog_VHDL GitHub Wiki
The if - else statement controls the execution of other statements. In programming language like c, if - else controls the flow of program. When more than one statement needs to be executed for an if condition, then we need to use begin and end as seen in earlier examples :
-
Syntax : if
if (condition) begin statements; end
-
Syntax : if-else
if (condition) begin statements; end else begin statements; end
-
Syntax : nested if-else-if
if (condition) statements; else if (condition) statements; ................ ................ else statements;
module simple_if();
reg latch;
wire enable,din;
always @ (enable or din)
if (enable) begin
latch <= din;
end
endmodule
module if_else();
reg dff;
wire clk,din,reset;
always @ (posedge clk)
if (reset) begin
dff <= 0;
end else begin
dff <= din;
end
endmodule
module nested_if();
reg [3:0] counter;
reg clk,reset,enable, up_en, down_en;
always @ (posedge clk)
// If reset is asserted
if (reset == 1'b0) begin
counter <= 4'b0000;
// If counter is enable and up count is asserted
end else if (enable == 1'b1 && up_en == 1'b1) begin
counter <= counter + 1'b1;
// If counter is enable and down count is asserted
end else if (enable == 1'b1 && down_en == 1'b1) begin
counter <= counter - 1'b1;
// If counting is disabled
end else begin
counter <= counter; // Redundant code
end
// Testbench code
initial begin
$monitor ("@%0dns reset=%b enable=%b up=%b down=%b count=%b",
$time, reset, enable, up_en, down_en,counter);
$display("@%0dns Driving all inputs to know state",$time);
clk = 0;
reset = 0;
enable = 0;
up_en = 0;
down_en = 0;
#3 reset = 1;
$display("@%0dns De-Asserting reset",$time);
#4 enable = 1;
$display("@%0dns De-Asserting reset",$time);
#4 up_en = 1;
$display("@%0dns Putting counter in up count mode",$time);
#10 up_en = 0;
down_en = 1;
$display("@%0dns Putting counter in down count mode",$time);
#8 $finish;
end
always #1 clk = ~clk;
endmodule
@0ns Driving all inputs to know state
@0ns reset=0 enable=0 up=0 down=0 count=xxxx
@1ns reset=0 enable=0 up=0 down=0 count=0000
@3ns De-Asserting reset
@3ns reset=1 enable=0 up=0 down=0 count=0000
@7ns De-Asserting reset
@7ns reset=1 enable=1 up=0 down=0 count=0000
@11ns Putting counter in up count mode
@11ns reset=1 enable=1 up=1 down=0 count=0001
@13ns reset=1 enable=1 up=1 down=0 count=0010
@15ns reset=1 enable=1 up=1 down=0 count=0011
@17ns reset=1 enable=1 up=1 down=0 count=0100
@19ns reset=1 enable=1 up=1 down=0 count=0101
@21ns Putting counter in down count mode
@21ns reset=1 enable=1 up=0 down=1 count=0100
@23ns reset=1 enable=1 up=0 down=1 count=0011
@25ns reset=1 enable=1 up=0 down=1 count=0010
@27ns reset=1 enable=1 up=0 down=1 count=0001
In the above example, the (enable == 1'b1 && up_en == 1'b1) is given highest priority and condition (enable == 1'b1 && down_en == 1'b1) is given lowest priority. We normally don't include reset checking in priority as this does not fall in the combo logic input to the flip-flop as shown in the figure below.
So when we need priority logic, we use nested if-else statements. On the other hand if we don't want to implement priority logic, knowing that only one input is active at a time (i.e. all inputs are mutually exclusive), then we can write the code as shown below.
It's known fact that priority implementation takes more logic to implement than parallel implementation. So if you know the inputs are mutually exclusive, then you can code the logic in parallel if.
module parallel_if();
reg [3:0] counter;
wire clk,reset,enable, up_en, down_en;
always @ (posedge clk)
// If reset is asserted
if (reset == 1'b0) begin
counter <= 4'b0000;
end else begin
// If counter is enable and up count is mode
if (enable == 1'b1 && up_en == 1'b1) begin
counter <= counter + 1'b1;
end
// If counter is enable and down count is mode
if (enable == 1'b1 && down_en == 1'b1) begin
counter <= counter - 1'b1;
end
end
endmodule
The case statement compares an expression to a series of cases and executes the statement or statement group associated with the first matching case:
space.gif
case statement supports single or multiple statements.
Group multiple statements using begin and end keywords.
-
Syntax of a case statement look as shown below.
case () < case1 > : < statement > < case2 > : < statement > ..... default : < statement > endcase
module mux (a,b,c,d,sel,y);
input a, b, c, d;
input [1:0] sel;
output y;
reg y;
always @ (a or b or c or d or sel)
case (sel)
0 : y = a;
1 : y = b;
2 : y = c;
3 : y = d;
default : $display("Error in SEL");
endcase
endmodule
module mux_without_default (a,b,c,d,sel,y);
input a, b, c, d;
input [1:0] sel;
output y;
reg y;
always @ (a or b or c or d or sel)
case (sel)
0 : y = a;
1 : y = b;
2 : y = c;
3 : y = d;
2'bxx,2'bx0,2'bx1,2'b0x,2'b1x,
2'bzz,2'bz0,2'bz1,2'b0z,2'b1z : $display("Error in SEL");
endcase
endmodule
The example above shows how to specify multiple case items as a single case item.
The Verilog case statement does an identity comparison (like the === operator); one can use the case statement to check for logic x and z values as shown in the example below.
module case_xz(enable);
input enable;
always @ (enable)
case(enable)
1'bz : $display ("enable is floating");
1'bx : $display ("enable is unknown");
default : $display ("enable is %b",enable);
endcase
endmodule
Special versions of the case statement allow the x ad z logic values to be used as "don't care":
casez : Treats z as don't care.
casex : Treats x and z as don't care.
module casez_example();
reg [3:0] opcode;
reg [1:0] a,b,c;
reg [1:0] out;
always @ (opcode or a or b or c)
casez(opcode)
4'b1zzx : begin // Don't care about lower 2:1 bit, bit 0 match with x
out = a;
$display("@%0dns 4'b1zzx is selected, opcode %b",$time,opcode);
end
4'b01?? : begin
out = b; // bit 1:0 is don't care
$display("@%0dns 4'b01?? is selected, opcode %b",$time,opcode);
end
4'b001? : begin // bit 0 is don't care
out = c;
$display("@%0dns 4'b001? is selected, opcode %b",$time,opcode);
end
default : begin
$display("@%0dns default is selected, opcode %b",$time,opcode);
end
endcase
// Testbench code goes here
always #2 a = $random;
always #2 b = $random;
always #2 c = $random;
initial begin
opcode = 0;
#2 opcode = 4'b101x;
#2 opcode = 4'b0101;
#2 opcode = 4'b0010;
#2 opcode = 4'b0000;
#2 $finish;
end
endmodule
@0ns default is selected, opcode 0000
@2ns 4'b1zzx is selected, opcode 101x
@4ns 4'b01?? is selected, opcode 0101
@6ns 4'b001? is selected, opcode 0010
@8ns default is selected, opcode 0000
module casex_example();
reg [3:0] opcode;
reg [1:0] a,b,c;
reg [1:0] out;
always @ (opcode or a or b or c)
casex(opcode)
4'b1zzx : begin // Don't care 2:0 bits
out = a;
$display("@%0dns 4'b1zzx is selected, opcode %b",$time,opcode);
end
4'b01?? : begin // bit 1:0 is don't care
out = b;
$display("@%0dns 4'b01?? is selected, opcode %b",$time,opcode);
end
4'b001? : begin // bit 0 is don't care
out = c;
$display("@%0dns 4'b001? is selected, opcode %b",$time,opcode);
end
default : begin
$display("@%0dns default is selected, opcode %b",$time,opcode);
end
endcase
// Testbench code goes here
always #2 a = $random;
always #2 b = $random;
always #2 c = $random;
initial begin
opcode = 0;
#2 opcode = 4'b101x;
#2 opcode = 4'b0101;
#2 opcode = 4'b0010;
#2 opcode = 4'b0000;
#2 $finish;
end
endmodule
@0ns default is selected, opcode 0000
@2ns 4'b1zzx is selected, opcode 101x
@4ns 4'b01?? is selected, opcode 0101
@6ns 4'b001? is selected, opcode 0010
@8ns default is selected, opcode 0000
module case_compare;
reg sel;
initial begin
#1 $display ("\n Driving 0");
sel = 0;
#1 $display ("\n Driving 1");
sel = 1;
#1 $display ("\n Driving x");
sel = 1'bx;
#1 $display ("\n Driving z");
sel = 1'bz;
#1 $finish;
end
always @ (sel)
case (sel)
1'b0 : $display("Normal : Logic 0 on sel");
1'b1 : $display("Normal : Logic 1 on sel");
1'bx : $display("Normal : Logic x on sel");
1'bz : $display("Normal : Logic z on sel");
endcase
always @ (sel)
casex (sel)
1'b0 : $display("CASEX : Logic 0 on sel");
1'b1 : $display("CASEX : Logic 1 on sel");
1'bx : $display("CASEX : Logic x on sel");
1'bz : $display("CASEX : Logic z on sel");
endcase
always @ (sel)
casez (sel)
1'b0 : $display("CASEZ : Logic 0 on sel");
1'b1 : $display("CASEZ : Logic 1 on sel");
1'bx : $display("CASEZ : Logic x on sel");
1'bz : $display("CASEZ : Logic z on sel");
endcase
endmodule
Driving 0
Normal : Logic 0 on sel
CASEX : Logic 0 on sel
CASEZ : Logic 0 on sel
Driving 1
Normal : Logic 1 on sel
CASEX : Logic 1 on sel
CASEZ : Logic 1 on sel
Driving x
Normal : Logic x on sel
CASEX : Logic 0 on sel
CASEZ : Logic x on sel
Driving z
Normal : Logic z on sel
CASEX : Logic 0 on sel
CASEZ : Logic 0 on sel
We assume that you understand case (casez, casex) statement as well as if-else statement. So, the focus is on full_case and parallel_case directives. The synthesis directives are added as a comment immediately after the case expression and before any of the case items as shown below.
case (case_expression) // synopsys full_case parallel_case
case_item1 : statement1;
case_item2 : statement2;
default : statement3;
endcase
In a full case statement, all possible values of case_expression can be matched to a case_item or to a case default. If case_expression does not match any of the case_item and case statement does not include case default, it’s not full case statement.
Consider the following examples 1(a) & 1(b). Both examples do not tell what happens to “dout” when sel = 2’b11.
For both examples, when sel = 2’b11, simulation will hold the last assigned value to “dout” i.e. the simulation results will be same but synthesis will produce different results.
For simulation, “// synopsys …” directive is merely a verilog comment and will be ignored. So, simulation results will remain same i.e. last assigned “dout” value. Since case statement in example 1(a) is not full, synthesis will infer a latch as shown below.
So, synthesis output will be last assigned “dout” value for sel = 2’b11 and hence there will be no simulation-synthesis mismatch.
In example 1(b), “synopsys …” directives are understood by synthesis tools. Tools like Synplicity and Precision interprets full_case directive to mean that if a case statement is not full, outputs are don’t cares for all unspecified case_items. So, dout = 1’bx for sel = 2’b11. This causes a functional mismatch between simulation and synthesis.
In a parallel case statement, case_expression matches to one and only one case_item. If the case_expression matches to more than one case_item, it’s not parallel case statement.
Consider the following examples 2(a) & 2(b). Here, multiple case_items match sel = 3’b011/3’b101/3’b110/3’b111.
Example 2(a) will simulate like a priority encoder where sel[2] has priority over sel[1] which has priority over sel[0]. Synthesis will also infer a priority encoder.
So, there will be no mismatch between simulation and synthesis.
Please note that sel[2] is MSB and sel[1] is LSB.
Example 2(b) will also simulate like a priority encoder because “// synopsys …” directive will be ignored. But synthesis tools recognize parallel_case directive and non-priority logic will be synthesized. This will cause functional mismatch between simulation and synthesis.