Variable Indexing
Constant Index vs Variable Index
Suppose we have:
input wire [255:0] in;
If we write:
in[5]
we are selecting one fixed bit.
The selected position is always:
bit 5
Therefore:
in[5]
↓
constant bit-select
↓
always selects the same bit
Now compare this with:
in[sel]
where sel is another signal.
For example:
input wire [7:0] sel;
Now the selected bit depends on the CURRENT VALUE of sel.
Therefore:
in[sel]
↓
variable bit-select
↓
selected bit can change during runtime
What Does a Variable Bit-Select Mean?
Suppose:
assign out = in[sel];
If:
sel = 0
then:
out = in[0]
If:
sel = 1
then:
out = in[1]
If:
sel = 2
then:
out = in[2]
and so on.
Therefore:
sel
↓
determines WHICH input bit is connected logically to out
Variable Selection Happens During Runtime
This is important.
The value of:
sel
is an ordinary runtime signal.
Therefore, the selected input can change while the hardware is operating.
Conceptually:
sel changes
↓
different position of in is selected
↓
out reflects the newly selected bit
This is fundamentally different from a constant index such as:
in[5]
where the selected location was fixed in the HDL description.
Variable Bit-Select as Multiplexer Behavior
Consider:
assign out = in[sel];
This can be understood as selection hardware.
Conceptually:
in[0] ─────┐
in[1] ─────┤
in[2] ─────┤
in[3] ─────┤
... ├── selection hardware ──→ out
in[255] ────┘
↑
sel
The hardware selects ONE input bit according to sel.
That is exactly the behavior of a MULTIPLEXER.
What Is the Multiplexer Interpretation?
A multiplexer chooses one input from several possible inputs.
The selector tells the mux which input should appear at the output.
Therefore:
assign out = in[sel];
can be interpreted as:
in
↓
collection of possible input bits
sel
↓
selector
out
↓
selected bit
This is why a variable bit-select can infer mux-like hardware.
Selector Width Determines Number of Possible Choices
Suppose:
sel
contains N bits.
An N-bit binary value can represent:
2^N
different values.
Therefore:
N selector bits
↓
up to 2^N selectable positions
Examples:
1 selector bit
↓
2 choices
2 selector bits
↓
4 choices
3 selector bits
↓
8 choices
4 selector bits
↓
16 choices
8 selector bits
↓
256 choices
Why Does an 8-Bit Selector Give 256 Choices?
An 8-bit unsigned value can represent:
0 through 255.
That gives:
256 total values.
Therefore:
input wire [7:0] sel;
can identify:
sel = 0
sel = 1
sel = 2
...
sel = 255
So if:
input wire [255:0] in;
then:
assign out = in[sel];
allows any one of the 256 bits to be selected.
256-to-1 Multiplexer Interpretation
Consider:
input wire [255:0] in;
input wire [7:0] sel;
output wire out;
assign out = in[sel];
Conceptually:
256 possible one-bit inputs
↓
8-bit selector
↓
choose one of 256
↓
one-bit output
Therefore, this describes behavior equivalent to a:
256-to-1
1-bit-wide
multiplexer
Why Is It Called 256-to-1?
The name:
256-to-1 mux
means:
256 possible input choices
↓
1 selected output
Only one input is selected at a time.
So:
256-to-1
does NOT mean:
256 bits are combined into one arithmetic result.
It means:
one of 256 choices is routed logically to the output.
Selection Width vs Data Width
A mux has two important ideas:
NUMBER OF CHOICES
and:
WIDTH OF EACH CHOICE
For:
assign out = in[sel];
each choice is:
1 bit wide.
Therefore:
256 choices
×
1 bit each
gives a:
256-to-1, 1-bit-wide mux.
But we can also select:
2-bit words
4-bit words
8-bit words
etc.
Then the mux still has the same number of choices, but each selected choice contains multiple bits.
Moving From Bit Selection to Word Selection
Suppose we want each selectable item to contain:
4 bits
instead of:
1 bit.
Then instead of selecting:
one bit
we need to select:
one 4-bit region.
For example:
sel = 0
↓
select bits [3:0]
sel = 1
↓
select bits [7:4]
sel = 2
↓
select bits [11:8]
sel = 3
↓
select bits [15:12]
and so on.
Using the Indexed Part-Select Learned Earlier
We previously learned indexed part-select syntax.
For this Session, we are using that existing knowledge in a NEW way.
Consider:
in[sel*4 +: 4]
The important new idea is:
sel
is a runtime selector.
Therefore, the starting position of the 4-bit selection changes dynamically.
The width remains:
4 bits.
Understanding sel*4
Suppose:
sel = 0
Then:
sel*4 = 0
Therefore:
in[sel*4 +: 4]
becomes:
in[0 +: 4]
which selects:
in[3:0]
If:
sel = 1
then:
sel*4 = 4
so:
in[4 +: 4]
selects:
in[7:4]
If:
sel = 2
then:
sel*4 = 8
so:
in[8 +: 4]
selects:
in[11:8]
Why Multiply sel by 4?
Each selectable word contains:
4 bits.
Therefore, neighboring words begin:
4 bits apart.
Word 0 begins at:
0
Word 1 begins at:
4
Word 2 begins at:
8
Word 3 begins at:
12
Therefore:
starting index = sel × 4
This maps the word number to the first bit position of that word.
Dynamic 4-Bit Word Selection
Consider:
assign out = in[sel*4 +: 4];
where:
out
is 4 bits wide.
Conceptually:
sel selects a WORD NUMBER.
The expression:
sel*4
calculates where that word begins.
Then:
+: 4
selects the four bits belonging to that word.
Therefore:
sel
↓
word number
sel*4
↓
starting bit position
4
↓
word width
out
↓
selected 4-bit word
Example Mapping
Suppose:
sel = 0
Then:
out = in[3:0]
sel = 1
Then:
out = in[7:4]
sel = 2
Then:
out = in[11:8]
sel = 3
Then:
out = in[15:12]
The selected region changes dynamically according to sel.
256 Four-Bit Inputs
Suppose we want:
256 selectable words
and each word contains:
4 bits.
Total packed input width:
256 × 4
=
1024 bits.
Therefore:
input wire [1023:0] in;
can contain:
256 separate 4-bit choices.
18. 1024-Bit Packed Input as 256 Four-Bit Words
Conceptually:
in[3:0]
↓
Word 0
in[7:4]
↓
Word 1
in[11:8]
↓
Word 2
...
in[1023:1020]
↓
Word 255
Therefore:
1024 packed bits
can be interpreted as:
256 groups
×
4 bits per group
Selecting One of 256 Four-Bit Words
Now consider:
input wire [1023:0] in;
input wire [7:0] sel;
output wire [3:0] out;
assign out = in[sel*4 +: 4];
The selector can represent:
0 through 255.
Therefore:
sel
chooses one of:
256 possible 4-bit words.
The output is:
4 bits wide.
So the hardware behavior corresponds to a:
256-to-1
4-bit-wide
multiplexer.
1-Bit-Wide vs 4-Bit-Wide Multiplexer
Compare:
assign out = in[sel];
with:
assign out = in[sel*4 +: 4];
FIRST:
in[sel]
selects:
one bit
Therefore:
256-to-1
1-bit-wide mux
SECOND:
in[sel*4 +: 4]
selects:
one 4-bit word
Therefore:
256-to-1
4-bit-wide mux
What Does '4-Bit-Wide Mux' Mean?
A 4-bit-wide mux does NOT mean there are only four inputs.
Instead:
each selectable input is itself:
4 bits wide.
Conceptually:
Input 0:
[a3 a2 a1 a0]
Input 1:
[b3 b2 b1 b0]
Input 2:
[c3 c2 c1 c0]
...
Selector chooses one complete 4-bit group.
Therefore, a:
256-to-1, 4-bit-wide mux
has:
256 possible data words
and:
each word contains 4 bits.
Multiplexer Width and Selector Width Are Different Things
Do not confuse:
SELECTOR WIDTH
with:
DATA WIDTH.
Example:
8-bit selector
↓
256 possible choices
4-bit output
↓
each selected choice contains 4 bits
Therefore:
selector width
determines
HOW MANY choices can be addressed
while:
data width
determines
HOW MANY bits are in each choice.
General Selector Relationship
If the number of choices is a power of two:
Number of choices = 2^(selector width)
For example:
2 choices
↓
1 selector bit
4 choices
↓
2 selector bits
8 choices
↓
3 selector bits
16 choices
↓
4 selector bits
256 choices
↓
8 selector bits
This relationship is fundamental when reading mux-selection code.
Packed Vector as a Collection of Choices
A packed vector can sometimes represent more than just one large binary number.
For mux applications, we can interpret it as a collection of smaller entries.
For example:
input [1023:0] in;
can be interpreted as:
one 1024-bit value
OR conceptually as:
256 separate 4-bit words
depending on how the design uses the vector.
This is an important hardware-description perspective.
Variable Bit-Select Does Not Mean a Physical Moving Wire
Consider:
assign out = in[sel];
Do NOT imagine:
one physical wire moves around inside the FPGA and attaches itself to a different input.
Instead:
the hardware contains selection logic.
The selector controls which available input influences the output.
Conceptually:
Multiple possible paths
↓
selection network
↓
out
The HDL Expression Describes Selection Behavior
The line:
assign out = in[sel];
is extremely short.
But the corresponding required hardware behavior may involve a large selection network.
This demonstrates an important HDL principle:
Small source-code expression
≠
small amount of hardware
The complexity depends on the function being described.
256-to-1 Selection Is Much Larger Than 2-to-1 Selection
Compare:
assign out = sel ? a : b;
with:
assign out = in[sel];
where:
in
contains 256 possible entries.
The first chooses between:
2 inputs.
The second can choose between:
256 inputs.
Both may look compact in Verilog, but their hardware-selection complexity is very different.
Multiplexer Inference
MULTIPLEXER INFERENCE means writing HDL behavior that causes synthesis to recognize that some form of selection hardware is required.
Examples include:
Ternary selection:
assign out = sel ? a : b;
Case-based selection:
case(sel)
...
endcase
Variable indexing:
assign out = in[sel];
These are different HDL descriptions that can all lead to mux-like selection structures when appropriate.
Variable Indexing Is a Very Compact Mux Description
Imagine manually writing a 256-way selector.
That would be extremely long.
Instead:
assign out = in[sel];
expresses the entire selection rule directly.
This is one advantage of HDL:
We describe the REQUIRED FUNCTION
rather than manually drawing every internal gate or mux stage.
What Happens if sel Changes?
Suppose:
sel = 5
Then:
out = in[5]
Later:
sel = 12
Then:
out = in[12]
Later:
sel = 200
Then:
out = in[200]
The hardware remains the same.
Only the runtime selection changes.
Therefore:
variable indexing
↓
dynamic selection using existing hardware
NOT:
dynamic hardware creation
Dynamic Selection vs Generate Selection
This distinction is useful because we studied generate constructs earlier.
VARIABLE INDEXING:
assign out = in[sel];
sel is a runtime signal.
Different inputs are selected while hardware operates.
GENERATE SELECTION:
Uses elaboration-time parameters/constants.
The hardware structure is determined before runtime.
Therefore:
Runtime mux selection
≠
Elaboration-time structural selection
Constant Selection May Require Much Less Selection Hardware
Consider:
assign out = in[5];
The source explicitly requests one fixed signal.
There is no runtime decision about which bit should be selected.
Now compare:
assign out = in[sel];
The selected bit can change.
Therefore, selection hardware is required to support all relevant choices.
This is the key hardware difference between constant and variable indexing.
Why Selector Range Matters
Suppose:
in
contains 256 valid positions:
0 through 255.
Then an 8-bit selector naturally represents exactly those positions.
But in other designs, a selector might be capable of representing values outside the number of available entries.
When designing such systems, we must consider what should happen for invalid selector values.
For the 256-entry and 8-bit-selector example:
all 256 selector values correspond naturally to valid positions.
Dynamic Word Selection Is Still Multiplexing
Do not think that multiplexers only select single bits.
A mux can select entire buses.
For:
assign out = in[sel*4 +: 4];
each selectable item is:
4 bits wide.
Conceptually, the selection happens in parallel for all four output bits.
Therefore:
mux
↓
can select scalar signals
or:
mux
↓
can select multi-bit buses
Parallel-Bit View of a 4-Bit-Wide Mux
A 4-bit-wide mux can also be imagined as four parallel muxes sharing the same selector.
Conceptually:
Bit 0 choices ──→ mux ──→ out[0]
Bit 1 choices ──→ mux ──→ out[1]
Bit 2 choices ──→ mux ──→ out[2]
Bit 3 choices ──→ mux ──→ out[3]
All four muxes use the same:
sel
Together, they select one complete 4-bit word.
36. Word Number vs Bit Number
This distinction becomes important in:
in[sel*4 +: 4]
Here:
sel
is being interpreted as:
WORD NUMBER
not:
direct bit number.
Then:
sel*4
converts:
word number
↓
starting bit number
For a 4-bit word:
word 0 → bit 0
word 1 → bit 4
word 2 → bit 8
word 3 → bit 12
General Dynamic Word-Selection Pattern
Suppose each word contains:
W bits.
Then a common pattern is conceptually:
input[start +: W]
where:
start = selector × W
Therefore:
selector
↓
chooses word number
selector × W
↓
converts word number into packed-vector starting index
W
↓
selects one complete word
Hardware Interpretation Is More Important Than Syntax Memorization
The most important goal is not simply to memorize:
in[sel]
or:
in[sel*4 +: 4]
Instead, ask:
"What hardware behavior does this expression require?"
For:
in[sel]
answer:
Select one bit from many possible bits.
For:
in[sel*4 +: 4]
answer:
Select one fixed-width word from many possible words.
That hardware interpretation is the key skill.
Common Mistake: Thinking sel Is Data Rather Than a Selector
In:
assign out = in[sel];
sel does not become part of the output value.
Instead:
sel tells the circuit WHICH location of in to select.
Therefore:
in
↓
data choices
sel
↓
selection control
out
↓
selected data
Common Mistake: Confusing Choice Count With Word Width
Suppose we have:
256-to-1, 4-bit-wide mux.
This means:
256 choices
and:
4 bits in each choice.
It does NOT mean:
4 choices selected by 256 bits.
Always separate:
NUMBER OF INPUT WORDS
from:
WIDTH OF EACH INPUT WORD
Common Mistake: Relearning '+:' Instead of Seeing the New Concept
The expression:
in[sel*4 +: 4]
uses indexed part-select syntax that we already learned previously.
The new concept here is NOT:
"What does +: mean?"
The new concept is:
A runtime selector can move the base of a fixed-width selection.
That creates dynamic multi-bit selection.
This is the important Session 3 extension.
Final Comparison
CONSTANT BIT-SELECT
Example:
in[5]
Meaning:
Always select one predetermined bit.
VARIABLE BIT-SELECT
Example:
in[sel]
Meaning:
Select one bit according to a runtime selector.
VARIABLE BIT-SELECT HARDWARE INTERPRETATION
Meaning:
Mux-like selection among many individual bits.
DYNAMIC WORD SELECTION
Example:
in[sel*4 +: 4]
Meaning:
Select one fixed-width word according to a runtime selector.
SELECTOR WIDTH
Meaning:
Determines how many distinct entries can be addressed.
DATA WIDTH
Meaning:
Determines how many bits are contained in each selectable entry.
256-TO-1, 1-BIT-WIDE MUX
Meaning:
Select one bit from 256 possible one-bit inputs.
256-TO-1, 4-BIT-WIDE MUX
Meaning:
Select one 4-bit word from 256 possible 4-bit words.
MULTIPLEXER INFERENCE
Meaning:
HDL behavior causes synthesis to recognize and implement required selection hardware.
43. Final Mental Model
Think about dynamic vector selection like this:
FIXED INDEX
in[5]
↓
The selected signal is predetermined.
VARIABLE INDEX
in[sel]
↓
sel changes at runtime
↓
Different bit is selected
↓
MUX-LIKE HARDWARE
For a 256-bit input:
8-bit sel
↓
256 possible selector values
↓
256 possible input bits
↓
256-to-1, 1-bit-wide selection
Now extend the same idea to words:
in[sel*4 +: 4]
↓
sel chooses the word number
↓
sel*4 calculates its starting bit
↓
4 bits are selected
↓
dynamic 4-bit word selection
For 256 four-bit words:
256 words
×
4 bits
=
1024 packed input bits
Therefore:
input [1023:0] in;
input [7:0] sel;
output [3:0] out;
assign out = in[sel*4 +: 4];
describes behavior corresponding to:
256 possible 4-bit words
↓
8-bit selector
↓
one selected 4-bit word
↓
out
The most important ideas are:
A CONSTANT INDEX SELECTS A FIXED VECTOR POSITION.
A VARIABLE INDEX SELECTS A POSITION DETERMINED BY A RUNTIME SIGNAL.
VARIABLE BIT-SELECTION CAN INFER MULTIPLEXER HARDWARE.
N SELECTOR BITS CAN REPRESENT UP TO 2^N DIFFERENT CHOICES.
AN 8-BIT SELECTOR CAN ADDRESS 256 DIFFERENT POSITIONS.
in[sel] OVER A 256-BIT VECTOR DESCRIBES 256-TO-1, 1-BIT-WIDE SELECTION.
A VARIABLE BASE WITH AN ALREADY-KNOWN INDEXED PART-SELECT CAN PERFORM DYNAMIC MULTI-BIT WORD SELECTION.
in[sel*4 +: 4] SELECTS ONE 4-BIT WORD ACCORDING TO sel.
256 FOUR-BIT WORDS REQUIRE 1024 PACKED INPUT BITS.
A 256-TO-1, 4-BIT-WIDE MUX HAS 256 POSSIBLE WORDS, EACH FOUR BITS WIDE.
SELECTOR WIDTH DETERMINES THE NUMBER OF CHOICES.
DATA WIDTH DETERMINES THE SIZE OF EACH CHOICE.
SHORT HDL EXPRESSIONS CAN DESCRIBE LARGE AMOUNTS OF SELECTION HARDWARE.
VARIABLE SELECTION CHANGES WHICH EXISTING HARDWARE PATH IS USED; IT DOES NOT CREATE NEW HARDWARE AT RUNTIME.