Conditional Selection

  1. Conditional Selection in Verilog

Conditional selection means choosing one result from multiple possible results depending on some condition.

Verilog provides several ways to describe this.

In this Note, the important ones are:

- Ternary operator

- case

- casez

These constructs all perform some form of selection, but they are useful in different situations.

Conceptually:

Condition or selector

Choose the appropriate result

Drive the required output

  1. The Ternary Operator

The TERNARY OPERATOR is a compact conditional expression.

Its general form is:

condition ? true_expression : false_expression

Conceptually:

Is the condition true?

YES → use true_expression

NO → use false_expression

For example:

assign out = sel ? a : b;

means:

If sel = 1

out = a

If sel = 0

out = b

  1. Breaking Down the Ternary Expression

Consider:

assign out = sel ? a : b;

There are three main parts.

CONDITION:

sel

TRUE EXPRESSION:

a

FALSE EXPRESSION:

b

Therefore:

sel ? a : b

means:

"If sel is true, choose a; otherwise choose b."

This is why the operator is called TERNARY:

It works with three main components.

  1. Ternary Operator as a Multiplexer Description

Consider:

assign out = sel ? a : b;

This describes two-way selection.

Conceptually:

a ─────┐

├── selection ──→ out

b ─────┘

sel

Therefore, a simple ternary expression commonly describes behavior equivalent to a 2-to-1 multiplexer.

If:

sel = 0

then:

out = b

If:

sel = 1

then:

out = a

  1. The Ternary Operator Does Not Automatically Mean Combinational Logic

This is important.

The ternary operator is an EXPRESSION.

Its surrounding context determines how that expression is being used.

For example:

assign out = sel ? a : b;

is a continuous assignment describing combinational selection.

But:

always @(posedge clk) begin

q <= toggle ? ~q : q;

end

uses a ternary expression inside clocked sequential logic.

Therefore:

TERNARY OPERATOR

Automatically combinational

The context matters.

  1. Ternary Operator Inside Clocked Logic

Consider:

always @(posedge clk) begin

q <= toggle ? ~q : q;

end

At every rising clock edge:

If:

toggle = 1

then:

q receives ~q

If:

toggle = 0

then:

q receives q

Conceptually:

toggle = 1

Toggle the stored value

toggle = 0

Keep the stored value

The ternary operator is simply choosing the next value of q.

  1. T-Flip-Flop Interpretation

The code:

q <= toggle ? ~q : q;

describes the basic behavior associated with a T-style flip-flop.

If:

toggle = 0

the output keeps its current value.

If:

toggle = 1

the output changes to its opposite value at the clock edge.

Conceptually:

toggle = 0

q_next = q

toggle = 1

q_next = NOT q

Again, the sequential behavior comes from:

always @(posedge clk)

not from the ternary operator itself.

  1. Nested Ternary Operators

A ternary expression can contain another ternary expression.

For example:

assign out = (sel == 2'b00) ? a :

(sel == 2'b01) ? b :

c;

This allows more than two possible results.

Conceptually:

Is sel == 00?

YES → out = a

NO

Is sel == 01?

YES → out = b

NO

out = c

  1. Nested Ternaries Have an Evaluation Order

Consider:

assign out = cond1 ? a :

cond2 ? b :

c;

Conceptually:

Check cond1 first.

If cond1 is true:

out = a

The later condition does not determine the selected result.

If cond1 is false:

check cond2.

If cond2 is true:

out = b

Otherwise:

out = c

Therefore, chained ternary expressions can describe PRIORITY.

The earlier condition has priority over later conditions.

  1. Ternary Operator for a 3-to-1 Multiplexer

Suppose we want three possible values:

a

b

c

and a selector chooses among them.

One possible description is:

assign out = (sel == 2'b00) ? a :

(sel == 2'b01) ? b :

c;

This behaves conceptually like:

sel = 00

a

sel = 01

b

otherwise

c

The ternary chain therefore provides compact multi-way selection.

  1. Ternary Operator for Minimum Selection

The ternary operator can also select according to a comparison.

For two values:

assign min_ab = (a < b) ? a : b;

Conceptually:

Is a < b?

YES → min_ab = a

NO → min_ab = b

Therefore, the ternary operator can select the smaller of two values.

  1. Four-Way Minimum Using Pairwise Comparison

Suppose we want the minimum of:

a

b

c

d

One clean strategy is:

min_ab = (a < b) ? a : b;

min_cd = (c < d) ? c : d;

min = (min_ab < min_cd) ? min_ab : min_cd;

Conceptually:

a ──┐

compare → min_ab ──┐

b ──┘ │

compare → min

c ──┐ │

compare → min_cd ──┘

d ──┘

This forms a comparison tree.

  1. Why the Pairwise Minimum Structure Is Useful

The pairwise structure breaks a larger decision into smaller decisions.

First:

choose between a and b

Then:

choose between c and d

Then:

choose between the two intermediate minima

This can make the logic easier to understand than one extremely long conditional expression.

The important idea is:

Different Verilog expressions can describe the same required function.

The best form is often the one that makes the intended behavior easiest to understand.

  1. Introducing 'case'

The 'case' statement provides multi-way selection.

General form:

case (expression)

value1:

statement1;

value2:

statement2;

value3:

statement3;

default:

default_statement;

endcase

Conceptually:

Evaluate expression

Compare it against the case items

Execute the matching branch

  1. Ordinary 'case' Uses Exact Matching

An ordinary:

case (...)

compares the case expression against the case items exactly.

Suppose:

case (scancode)

8'h6B:

left = 1'b1;

8'h72:

down = 1'b1;

8'h74:

right = 1'b1;

8'h75:

up = 1'b1;

endcase

For a branch to match:

the required value must match the complete case item according to ordinary case matching.

This makes ordinary case useful when each complete value has a distinct meaning.

  1. Why Exact Matching Matters for Scancodes

Keyboard scancodes represent specific codes.

For example, two arrow keys may have values that differ by only one or a few bits.

But that difference is still meaningful.

Conceptually:

scancode A

scancode B

even if most bits happen to be identical.

Therefore, when the entire scancode is meaningful:

EXACT MATCHING

is usually the appropriate mental model.

  1. Introducing 'casez'

'casez' is similar to 'case', but it allows wildcard-style matching involving z/? positions.

Example:

casez (opcode)

8'b0001_????:

operation1;

8'b0010_????:

operation2;

endcase

The question marks mean:

These positions do not need to match a specific 0 or 1 value.

Therefore:

0001_0000

0001_0001

0001_1010

0001_1111

can all match:

0001_????

  1. What Does '?' Mean in a 'casez' Pattern?

Inside an appropriate 'casez' case item:

?

acts as a DON'T-CARE / WILDCARD position.

Example:

8'b1010_????

means:

The upper four bits must match:

1010

but the lower four bits may vary.

Conceptually:

1010 xxxx

where x means:

"Either value is acceptable for matching."

  1. Exact Matching vs Wildcard Matching

ORDINARY 'case'

Example:

8'b1010_0110

Meaning:

Match the complete specified value.

'casez'

Example:

8'b1010_????

Meaning:

Match any value whose relevant upper bits are 1010.

Therefore:

case

Exact-value selection

casez

Pattern-based selection with intentionally ignored positions

  1. One Wildcard Pattern Can Match Many Values

Suppose the pattern is:

8'b1100_????

The four wildcard positions can independently be 0 or 1.

Therefore:

2^4 = 16

different binary values can match this one pattern.

This is the power of wildcard matching.

It is also the danger.

A wildcard pattern can be much broader than it appears if you are not careful.

  1. Why Wildcards Can Be Dangerous in Exact Decoding

Suppose you are decoding keyboard scancodes.

You want:

one exact scancode

one exact output

If you replace meaningful bits with:

?

then the pattern may accidentally match several scancodes.

Conceptually:

Intended value

Make several distinguishing bits wildcards

Pattern becomes broader

Other unintended values also match

The synthesizer is not "confused."

The HDL description itself specified a broader match than intended.

  1. Incorrect Decoder vs Incorrect Hardware

This distinction is extremely important.

If a 'casez' pattern unintentionally matches multiple scancodes, and the synthesized circuit activates the wrong output for one of those scancodes:

the hardware may still be correctly implementing the Verilog.

The real problem is:

THE DESCRIPTION WAS WRONG.

Therefore:

Unexpected circuit behavior

does not automatically mean

the FPGA malfunctioned.

Sometimes:

Verilog description

correctly synthesized

undesired behavior

because the original logic specification was incorrect.

  1. Overlapping 'casez' Patterns

Two wildcard patterns can overlap.

That means:

the same input value may satisfy more than one case item.

For example, imagine:

1??0

and:

10??

Some binary values can potentially satisfy both patterns.

When that happens, ordering becomes important.

  1. First Matching Branch Wins

In a prioritized pattern-selection situation with overlapping 'casez' items, the earlier matching case item takes precedence.

Conceptually:

Check pattern 1

Matches?

YES → choose it

If not:

Check pattern 2

If not:

Check pattern 3

Therefore, source order can create PRIORITY between overlapping wildcard patterns.

  1. Broad Pattern vs Specific Pattern

Suppose one pattern is very broad:

1???

and another is more specific:

101?

Every value matching:

101?

also matches:

1???

If the broad pattern is placed first, it may capture values before the more specific pattern is reached.

Therefore, when overlapping wildcard patterns are intentional:

ORDER MATTERS.

A common reasoning principle is:

More specific conditions may need to appear before broader ones when priority should favor the specific case.

  1. 'casez' and Priority Encoders

Wildcard matching is useful when some lower-priority information genuinely does not matter.

A priority encoder is a good example.

Suppose the highest-order asserted bit should determine the result.

If the highest-priority bit is already 1:

lower-priority bits may be irrelevant.

A pattern such as:

1???

can intentionally mean:

"The highest-priority bit is set; I do not care about the lower bits."

This is an appropriate use of wildcards.

  1. 'casez' for Opcode Families

Another good use is when a group of codes shares meaningful upper bits while lower bits represent something irrelevant to the current decoder.

Example:

casez (opcode)

8'b0001_????:

class1;

8'b0010_????:

class2;

8'b0011_????:

class3;

endcase

Here:

upper bits

identify operation family

lower bits

intentionally ignored by this decoder

This is a legitimate pattern-matching application.

  1. When Should Ordinary 'case' Be Preferred?

Use ordinary exact matching when the complete value matters.

Examples:

- Exact keyboard scancode

- Exact command value

- Exact state encoding

- Exact constant selector value

Conceptually:

If changing one bit can change the meaning

Do not casually wildcard that bit.

  1. When Should 'casez' Be Considered?

'casez' is useful when:

- Some positions intentionally do not matter

- Several values belong to the same pattern class

- Priority-style pattern matching is desired

- A decoder should classify value families rather than exact values

The key question is:

"Are the wildcarded bits genuinely irrelevant?"

If not, wildcarding them is dangerous.

  1. What Is 'default'?

A 'case' or 'casez' statement can include:

default:

The default branch handles values that do not match any earlier case item.

Example:

case (sel)

2'b00:

out = a;

2'b01:

out = b;

default:

out = c;

endcase

Conceptually:

No listed case item matched

Use the default branch

  1. What Does 'default: ;' Mean?

Consider:

default: ;

The semicolon means:

There is no assignment or other substantive statement in that branch.

Conceptually:

No listed case item matched

Default branch selected

Do nothing inside the case branch

This does NOT automatically mean:

"Set every output to zero."

It simply means:

The default branch itself performs no assignment.

  1. Why Can 'default: ;' Sometimes Be Safe?

Consider:

always @(*) begin

left = 1'b0;

down = 1'b0;

right = 1'b0;

up = 1'b0;

case (scancode)

8'h6B:

left = 1'b1;

8'h72:

down = 1'b1;

8'h74:

right = 1'b1;

8'h75:

up = 1'b1;

default:

;

endcase

end

Before the case statement begins:

ALL outputs already received values.

Therefore, if no case item matches:

default does nothing

and the outputs remain at their previously assigned values from the current combinational evaluation:

left = 0

down = 0

right = 0

up = 0

  1. Default First, Then Override

The previous example follows an important combinational coding pattern:

DEFAULT FIRST

OVERRIDE WHEN NECESSARY

Conceptually:

Step 1:

Give every output a safe default value.

Step 2:

Evaluate selection logic.

Step 3:

Override only the outputs that should change.

Example:

left = 0;

down = 0;

right = 0;

up = 0;

case (scancode)

LEFT_CODE:

left = 1;

DOWN_CODE:

down = 1;

...

endcase

This style makes the intended behavior easy to follow.

  1. Why an Empty 'default' Can Be Dangerous Without Prior Assignments

Consider a different situation:

always @(*) begin

case (sel)

2'b00:

out = a;

2'b01:

out = b;

default:

;

endcase

end

If sel matches neither listed value:

the block provides no new assignment to out along that path.

Now the hardware description may require out to retain its previous value.

In combinational logic, that is generally a sign of unintended storage behavior.

The detailed latch concept was already learned earlier.

The important new point here is:

'default: ;' is only safe when the surrounding combinational assignments already define the required output behavior.

  1. 'default' Does Not Replace Proper Combinational Assignment

A common misconception would be:

"If I wrote a default branch, my combinational block must automatically be complete."

That is not true.

The important question is:

Does every relevant output receive a defined value along every possible execution path?

A default branch can help.

Pre-assigning defaults can help.

But simply writing the word:

default

does not automatically guarantee correct combinational behavior.

  1. Ternary vs 'case'

Both can describe selection.

A ternary is especially compact for:

two-way selection

Example:

assign out = sel ? a : b;

A 'case' statement is often clearer for:

many distinct selector values

Example:

case (sel)

2'b00: out = a;

2'b01: out = b;

2'b10: out = c;

2'b11: out = d;

endcase

Therefore, the choice is often about:

clarity

+

the kind of selection being described.

  1. 'case' vs 'casez'

Use:

case

when:

complete exact values matter.

Use:

casez

when:

some bit positions are intentionally irrelevant and wildcard pattern matching is desired.

Conceptually:

case

"What exact value is this?"

casez

"What pattern does this value belong to?"

  1. Ternary vs 'casez'

TERNARY

Most naturally expresses conditional value selection.

Example:

sel ? a : b

'casez'

Most naturally expresses pattern-based multi-way selection.

Example:

casez(opcode)

8'b0001_????: ...

8'b0010_????: ...

endcase

Both are forms of selection, but they solve different kinds of selection problems.

  1. Priority Can Appear in More Than One Form

Priority is not exclusive to 'casez'.

For example:

cond1 ? a :

cond2 ? b :

c

checks:

cond1 first

then:

cond2

Therefore, nested ternaries can also have a priority interpretation.

Similarly, overlapping wildcard patterns in 'casez' can create source-order priority.

So when reading selection logic, ask:

"Can more than one condition potentially match?"

If YES:

priority/order may matter.

  1. Exact Decoder vs Pattern Decoder

EXACT DECODER

Input:

Complete value

Behavior:

Match exact codes

Typical construct:

case

PATTERN DECODER

Input:

Value containing relevant and irrelevant fields

Behavior:

Classify according to selected bit patterns

Typical construct:

casez

Example:

Keyboard arrow scancode

Exact decoder

Opcode family with ignored low bits

Pattern decoder

  1. Common Mistake: Wildcarding Bits Merely to Shorten the Code

Wildcards should represent:

ACTUALLY IRRELEVANT INFORMATION.

They should not be used simply because:

"The patterns look similar, so I can replace the differences with question marks."

If those differences distinguish real meanings, wildcarding them changes the logic specification.

Therefore:

Similar-looking binary values

Permission to ignore their differing bits

  1. Common Mistake: Assuming the Most Specific Matching Pattern Wins Automatically

Suppose two 'casez' patterns both match.

Do not assume the simulator/synthesizer automatically chooses whichever pattern "looks more specific."

Priority depends on the actual case-item ordering.

Therefore:

Specificity

Automatic priority

Source order matters when patterns overlap.

  1. Common Mistake: Treating 'default: ;' as Zero Assignment

Again:

default: ;

means:

perform no statement in that branch.

It does NOT mean:

out = 0;

unless out was already assigned 0 elsewhere in the block.

Always distinguish:

DO NOTHING

from:

ASSIGN ZERO

  1. Common Mistake: Assuming Ternary Means Mux Hardware in Every Context

A ternary expression often helps us conceptualize selection as a mux.

But:

q <= toggle ? ~q : q;

appears inside clocked sequential logic.

The resulting hardware behavior includes state.

Therefore, the better rule is:

TERNARY

conditional expression

The surrounding HDL context determines how that expression contributes to the resulting hardware.

  1. Final Comparison

TERNARY OPERATOR

Syntax:

condition ? true_expression : false_expression

Main purpose:

Compact conditional value selection.

NESTED TERNARY

Main purpose:

Multiple ordered conditional selections.

Potential property:

Priority based on condition order.

'case'

Main purpose:

Multi-way exact-value selection.

'casez'

Main purpose:

Multi-way wildcard/pattern selection.

'?'

Inside an appropriate 'casez' item:

Wildcard / don't-care position.

OVERLAPPING PATTERNS

Meaning:

More than one wildcard pattern can potentially match the same value.

FIRST-MATCH PRIORITY

Meaning:

When overlapping patterns are used, earlier matching items have priority.

'default'

Meaning:

Handles values that match no listed case item.

'default: ;'

Meaning:

The default branch performs no assignment itself.

DEFAULT-FIRST / OVERRIDE-LATER

Meaning:

Assign safe combinational defaults before selection logic and override them only when required.

  1. Final Mental Model

Think about Session 3 conditional selection like this:

TWO-WAY VALUE SELECTION

Ternary operator

condition ? a : b

MULTI-WAY EXACT SELECTION

case

Match complete values

MULTI-WAY PATTERN SELECTION

casez

Match values while intentionally ignoring selected positions

For wildcard matching:

Pattern

Required bits must match

Wildcard bits do not distinguish values

One pattern may match several inputs

If patterns overlap:

Earlier match

Higher priority

For combinational case logic:

Assign safe defaults first

Enter case

Override outputs when a specific selection matches

The most important ideas are:

THE TERNARY OPERATOR IS A CONDITIONAL EXPRESSION, NOT A GUARANTEE OF COMBINATIONAL HARDWARE.

A SIMPLE TERNARY EXPRESSION OFTEN DESCRIBES TWO-WAY MUX-LIKE SELECTION.

NESTED TERNARIES CAN EXPRESS ORDERED/PRIORITY SELECTION.

ORDINARY 'case' IS APPROPRIATE WHEN COMPLETE VALUES MUST MATCH EXACTLY.

'casez' ALLOWS WILDCARD/PATTERN MATCHING.

'?' CAN REPRESENT AN INTENTIONALLY IGNORED BIT POSITION IN A 'casez' PATTERN.

WILDCARDS SHOULD ONLY REPLACE BITS THAT GENUINELY DO NOT MATTER.

OVERLY BROAD WILDCARDS CAN CAUSE UNINTENDED VALUES TO MATCH.

OVERLAPPING WILDCARD PATTERNS CREATE PRIORITY BASED ON CASE-ITEM ORDER.

THE FIRST MATCHING CASE ITEM WINS WHEN MULTIPLE PATTERNS CAN MATCH.

EXACT SCANCODES ARE BETTER SUITED TO EXACT MATCHING THAN CARELESS WILDCARD MATCHING.

'default: ;' MEANS THE DEFAULT BRANCH ITSELF DOES NOTHING.

AN EMPTY DEFAULT CAN BE SAFE WHEN OUTPUTS HAVE ALREADY RECEIVED COMPLETE SAFE DEFAULT ASSIGNMENTS.

DEFAULT-FIRST / OVERRIDE-LATER IS A CLEAN WAY TO ORGANIZE COMBINATIONAL DECODER LOGIC.

VERILOG DOES EXACTLY THE SELECTION BEHAVIOR YOU DESCRIBE; A BAD PATTERN CAN SYNTHESIZE PERFECTLY INTO THE WRONG FUNCTION YOU ACCIDENTALLY SPECIFIED.