Conditional Statements in Verilog
Conditional statements in a programming language help to branch the execution of code depending on some condition. In simpler words, using these statements, the execution of specific code lines can be controlled using some conditions. Verilog provides two types of conditional statements, namely
- If-else
- Case statement
Let us explore both statements in detail.
If-else
If-else is the most straightforward conditional statement construct. For the compiler, this statement means that “If some condition is true, execute code inside if or else execute codes inside else.” The condition evaluates to be true if the argument is a non-zero number. In if-else, it is not necessary to always have an else block.
Branching of code in if-else
Syntax:
If-else-if
If-else-if construct is used when more than one condition needs to be checked. All the conditions are checked serially, and if none of the conditions is true, then the else block is executed.
Branching of code in if-else-if
Syntax:
Case Statements
Case statements are generally used when the condition is an equivalence check, which means “==” or “===”. Case statement makes the code more readable wrt to if-else if there are many conditions to check. As the name indicates, this statement will switch a particular case based on some arguments.
Syntax:
Again, to account for the four-state variables, there are three case statement variants: case, casez, and casex. Let us look at them in detail and also find out the difference.
Case
In the case statement, exact matching is done. If even a single bit does not match the cases defined, the default case will be executed.
Output
Casez
In the previous statement, we have seen that a case will be executed if it matches precisely with the argument. However, in many cases, we would not want to match the cases exactly. Consider a simple example where the master uses a select signal to select a particular slave amongst many (say, four slaves). Thus, the select line would be a 4-bit signal. A single bit needs to be high to select any slave, and the rest of the bits can be anything. Thus, instead of writing multiple cases for a slave, we can use casez. In casez, the z or ‘?’ is does not care, which means it will not be considered while comparing the case with the argument.
Example
Output
Casex
Casex is a bit more flexible than casez. In casex, even X is not considered during case comparison. Thus, X, Z, ? all are considered as do not care in casex. Let us see the difference between all these case statements using an example.
Example
In the below example, the same operations are performed in different always block but using a different case statement. In the output, it can be seen that, if the value of the argument, i.e., op_code is X, then default case is executed in the case and casez construct, but for casex, the X is considered as do not care, and thus the first case is executed.
When the op_code is Z, then only in the case construct the default case is executed, and for the casex and casez, Z is considered as do not care, and the 1st case is executed.
Output
All three case statements are synthesizable, but it is not recommended to use casex and casez in designs. It is because the output after synthesis and during the simulation can differ in casex and casez. Case statements come in behavioural modelling (we will learn more about in future topics), and for complex behavioural logics, the synthesis can be different in different tools.