Verilog · Chapter 5.2.4 · Data & Variables
Scalar vs Vector vs Arrays in Verilog
Every Verilog variable has a dimension, which is one bit, multiple bits packed together, or multiple instances of a packed value. That choice helps determine what hardware the synthesis tool produces. A scalar reg is one flop, a vector reg is a row of flops, and an array of regs is many rows of flops or an inferred SRAM macro when the count is large. The same vocabulary applies to nets such as wire, since every net type supports the same scalar, vector, and array forms with the same rules. This page closes the section by walking through each form, how to access individual bits or groups of bits, the indexed part-selects added in Verilog-2001, the memory-declaration form for register files and SRAMs, and the per-bit and per-entry distinctions that catch beginners.
Foundation22 min readVerilogScalarVectorArrayMemoryBit-Select
Chapter 5 · Section 5.2.4 · Data & Variables
1. The Engineering Problem
A junior engineer needs to declare a 32-bit data path that carries one of four 8-bit values, selected by a 2-bit selector. They write:
reg sel0, sel1; // 2-bit selector — scalar form
reg val00, val01, val02, val03, val04, val05, val06, val07; // first byte
reg val10, val11, val12, val13, val14, val15, val16, val17; // second byte
// ... 32 individual signals ...The code compiles, but the engineer has invented their own naming convention, scattered the signals across 32 declarations, and now every operation on the data path requires 32 individual assignments. A simple mux becomes 256 lines of code; a 4-input adder becomes pages.
The same design with proper dimension usage:
reg [1:0] sel; // 2-bit selector — vector form
reg [7:0] data [0:3]; // 4-entry × 8-bit memory — array form
reg [7:0] mux_out; // 8-bit mux output — vector
// The mux:
always @(*) mux_out = data[sel]; // 1 line, not 256sel is now a 2-bit vector (one declaration); data is a 4-entry 8-bit memory (one declaration); the mux is one line of array-indexed access. The synthesis tool produces the same gates as the scalar-form version, but the code is readable, maintainable, and concise.
This page is about picking the right dimension for each signal — scalar when one bit is needed, vector for multi-bit single values, array for multiple instances of a value. Get the dimension right and the rest of the design writes itself; get it wrong and you spend weeks managing the consequences.
2. The Three Dimensions
Verilog supports exactly three dimensions for any variable or net:
| Dimension | Syntax | Bits | Use case |
|---|---|---|---|
| Scalar | reg q; | 1 bit | Single-bit flags, enables, valid signals |
| Vector | reg [N-1:0] q; | N bits, packed | Multi-bit values: counters, addresses, data paths |
| Array | reg [N-1:0] q [0:M-1]; | N×M bits | Multiple entries: register files, SRAMs, lookup tables |
The same syntax applies to nets (wire, tri, etc.) — wire [7:0] data; declares an 8-bit vector wire; wire [7:0] bus [0:15]; declares a 16-entry × 8-bit array of wires (rare but legal).
The dimension determines the variable's shape in the simulator's memory and the hardware the synthesis tool produces:
- Scalar → 1 flop (or 1 piece of combinational logic).
- Vector → N flops (or N pieces of combinational logic, all in parallel).
- Array → N×M flops (or an inferred SRAM macro for large M).
3. Mental Model
The mental-model has three practical consequences:
- Range ordering convention is
[MSB:LSB]for vectors. Convention is[N-1:0](descending) — bit N-1 is the most significant, bit 0 is the least. Reversing to[0:N-1](ascending) is legal but produces byte-order bugs when modules disagree. - Range ordering convention is
[0:M-1]for arrays. Convention is[0:M-1](ascending) — entry 0 is the first, entry M-1 is the last. Reversing to[M-1:0]is legal but produces "address goes the wrong way" bugs. - You cannot slice across array entries.
mem[3:5]is illegal — Verilog requires accessing one entry at a time. To touch three entries, you write three statements (or a loop).
4. Scalar — the 1-bit Form
The simplest dimension. One bit, no brackets, no surprises.
`default_nettype none
reg valid; // single-bit valid flag
reg ready; // single-bit ready flag
reg en; // enable
reg rst_n; // active-low reset
wire gated_clk; // single-bit clock signal
wire irq; // interrupt signalScalar regs and wires are the most-used type in any RTL design — every enable, every valid signal, every flag, every single-bit clock-domain signal is scalar. The synthesis tool produces one flop per scalar reg in a clocked always; one wire's worth of metal per scalar wire driven by an assign.
The arithmetic operators on scalars produce single-bit results:
wire a, b, y, z;
assign y = a & b; // single-bit AND
assign z = a | b; // single-bit ORComparisons between scalars produce single-bit results. Concatenations of scalars produce vectors: {a, b, c} is a 3-bit vector with a as the MSB.
5. Vector — the Packed Multi-bit Form
The workhorse dimension. Multiple bits packed into a single variable with a contiguous range.
`default_nettype none
reg [7:0] count; // 8-bit unsigned counter
reg [31:0] addr; // 32-bit address
reg [11:0] data; // 12-bit data path
reg [N-1:0] param_vec; // parametric width
wire [15:0] result; // 16-bit combinational output
// Less-common ascending range
reg [0:7] byte_a; // 8 bits, bit 0 MSB, bit 7 LSBThe range [MSB:LSB] declares which bit is the most significant. The convention [N-1:0] (descending) is universal across every working RTL house — it matches the standard mathematical convention that "the index is the bit weight." A reg [7:0] count; has bit 7 representing 2^7 = 128 and bit 0 representing 2^0 = 1.
5.1 Bit-select
Accessing a single bit:
reg [7:0] data = 8'b1010_0110;
data[0] // = 1'b0 (LSB)
data[3] // = 1'b0
data[7] // = 1'b1 (MSB)
data[8] // = 1'bx (out of range — Verilog returns X for out-of-range bit-select)Variable bit-select:
reg [7:0] data;
reg [2:0] idx; // 0 to 7
reg bit_value;
assign bit_value = data[idx]; // dynamic bit selectThe dynamic index idx is computed at simulation time. If idx is out of range, the result is X. The synthesis tool generates a mux: bit_value = data[7] when idx=7, data[6] when idx=6, etc.
5.2 Part-select (fixed range)
Accessing a contiguous range of bits:
reg [31:0] data = 32'h1234_5678;
data[7:0] // = 8'h78 (lower byte)
data[15:8] // = 8'h56 (next byte)
data[31:24] // = 8'h12 (upper byte)
data[31:0] // = 32'h1234_5678 (the entire value)
data[3:0] // = 4'h8 (lower nibble)
data[23:0] // = 24'h34_5678The selected range must be literal constant — data[3:0] is legal, but data[idx+3:idx] is not (this is what the indexed part-selects in §5.3 are for).
5.3 Indexed part-select (Verilog-2001)
Verilog-2001 added two operators for accessing variable-base ranges:
base+:width— base is the LSB of the slice, width is the number of bits.base-:width— base is the MSB of the slice, width is the number of bits.
reg [31:0] data = 32'h1234_5678;
reg [3:0] word_idx;
// Fixed-width 8-bit slice with variable base
data[0 +: 8] // = data[7:0] = 8'h78
data[8 +: 8] // = data[15:8] = 8'h56
data[16 +: 8] // = data[23:16] = 8'h34
data[word_idx*8 +: 8] // dynamic byte select
// Or the -: form for "MSB first":
data[31 -: 8] // = data[31:24] = 8'h12
data[23 -: 8] // = data[23:16] = 8'h34The width must be a constant; the base can be a variable expression. This is the canonical way to do byte-by-byte access of a wide word — data[byte_idx*8 +: 8] extracts the byte_idx-th byte regardless of the value of byte_idx at simulation time.
`default_nettype none
module byte_extractor (
input wire [31:0] data,
input wire [1:0] byte_idx, // 0..3
output wire [7:0] byte_out
);
assign byte_out = data[byte_idx*8 +: 8];
endmoduleSynthesis output: a 4-input mux on the 8-bit width, with byte_idx as the select. The dynamic byte access is the canonical use of +:.
6. Array — the Multi-entry Form
The third dimension. Multiple vector entries, each addressable by a separate index.
`default_nettype none
reg [7:0] mem [0:255]; // 256-entry × 8-bit byte memory
reg [31:0] rf [0:31]; // 32-entry × 32-bit register file
reg [15:0] table_q [0:1023]; // 1K-entry × 16-bit lookup table
// Parametric memory
parameter DEPTH = 1024;
parameter WIDTH = 16;
reg [WIDTH-1:0] data_mem [0:DEPTH-1];
// Multi-dimensional array (Verilog-2001 supports limited multi-dim)
reg [7:0] cube [0:3][0:3]; // 4×4 grid of 8-bit valuesThe first dimension [WIDTH-1:0] (before the name) is the word width — bits per entry. The second dimension [0:DEPTH-1] (after the name) is the depth — number of entries.
6.1 Array indexing
reg [7:0] mem [0:255];
mem[0] // 8-bit value at address 0
mem[100] // 8-bit value at address 100
mem[addr] // dynamic addressing
mem[addr][3:0] // lower nibble of the entry at addr
mem[addr][bit_idx] // single bit at (addr, bit_idx)The two-step indexing — first the entry, then a bit or part-select within the entry — is the canonical pattern for "memory at address X, bit Y."
6.2 What you cannot do with arrays
Three operations are illegal on Verilog arrays (Verilog-2001):
- Slicing across entries.
mem[3:5]is illegal — you cannot get a sub-range of entries as a single value. - Assigning the entire array as a single literal.
mem = '{default:0};is SystemVerilog, not Verilog. In Verilog you must initialise entry-by-entry via a generate loop, aninitialblock with explicit assignments, or$readmemh()/$readmemb()to load from a file. - Passing the entire array as a port. Verilog-2001 does not allow
output reg [7:0] mem [0:255]in a port list. To export memory from a module, expose individual entries via dedicated ports, or use a memory-export side channel (a debug/backdoorinterface).
The SystemVerilog extensions (covered in the SystemVerilog track) lift these restrictions; for pure Verilog-2001, the restrictions are real.
6.3 Initialisation
Arrays have no implicit initialisation — every entry is X on every bit at t = 0. Three ways to set them up:
// (1) In a clocked always block (synthesisable reset path)
integer i;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
for (i = 0; i < 256; i = i + 1) mem[i] <= 8'h00;
end else if (wr_en) begin
mem[addr] <= wr_data;
end
end
// (2) In an initial block (testbench-only or large memories)
integer i;
initial begin
for (i = 0; i < 256; i = i + 1) mem[i] = 8'h00;
end
// (3) From a file (testbench-only — synthesisable in some tools)
initial $readmemh("mem_init.hex", mem); // hex file
initial $readmemb("mem_init.bin", mem); // binary fileThe $readmemh() form is the canonical way to initialise large memories in testbenches; the file format is one entry per line, in hex ($readmemh) or binary ($readmemb). Some FPGA flows (Xilinx Vivado, Intel Quartus) accept $readmemh() in synthesisable RTL — the tool reads the file at synthesis time and embeds the values as initial flop states or BRAM init values.
7. Visual Explanation
Three figures cover the dimension hierarchy.
7.1 Visual A — the three shapes
A side-by-side picture of the three dimensions on the same logical 8-bit data.
Three dimensions of Verilog variables
data flow7.2 Visual B — bit-select and part-select operators
The access syntax for a vector. Four ways to access bits within a 32-bit vector.
7.3 Visual C — array structure
The structural view of a memory: M entries side by side, each an N-bit vector. Address selects the entry; bit-select within the entry picks a bit.
8. The Concatenation and Replication Operators
A vector can be built from smaller pieces using concatenation { , } and replication {N{ }}. These are essential for byte-packing and width-conversion.
8.1 Concatenation
reg [3:0] nibble_high = 4'hA;
reg [3:0] nibble_low = 4'h5;
reg [7:0] byte_val;
byte_val = {nibble_high, nibble_low}; // = 8'hA5
// More general
reg [31:0] word;
word = {byte_val, 24'h00_00_00}; // = 32'hA5_00_00_00
// Mix scalars and vectors
reg sign_bit = 1'b1;
reg [6:0] mantissa = 7'b1010101;
reg [7:0] composite = {sign_bit, mantissa}; // = 8'b1101_0101Concatenation builds a vector left-to-right: the first argument is the MSB. The total width is the sum of the argument widths.
8.2 Replication
reg [3:0] pattern = 4'h5;
reg [15:0] replicated;
replicated = {4{pattern}}; // = 16'h5555 (= 4 copies of 4'h5)
// Common pattern: sign-extension
reg [7:0] signed_byte = 8'h80; // = -128 in two's complement
reg [31:0] sign_extended;
sign_extended = {{24{signed_byte[7]}}, signed_byte}; // = 32'hFFFF_FF80
// Common pattern: zero-padding
reg [15:0] zero_padded;
zero_padded = {8'h00, signed_byte}; // = 16'h0080Replication is the canonical way to sign-extend or zero-extend a narrow value into a wider one. The {{24{signed_byte[7]}}, signed_byte} idiom is standard for "sign-extend an 8-bit signed value to 32 bits."
8.3 The reverse: distributing a vector
There's no direct "reverse concatenation" operator. To split a vector into pieces, use part-selects:
reg [31:0] word = 32'hAABB_CCDD;
reg [7:0] byte0 = word[7:0]; // = 8'hDD
reg [7:0] byte1 = word[15:8]; // = 8'hCC
reg [7:0] byte2 = word[23:16]; // = 8'hBB
reg [7:0] byte3 = word[31:24]; // = 8'hAAThe pattern is straightforward — one part-select per piece. For an array of bytes, a generate loop or for loop assigns each byte from a different part-select of the source word.
9. Multi-dimensional Arrays
Verilog-2001 added limited support for multi-dimensional arrays — declarations with more than one post-name range.
`default_nettype none
reg [7:0] cube [0:3][0:3]; // 4×4 grid of 8-bit values
reg [7:0] tensor [0:3][0:3][0:3]; // 4×4×4 cube of 8-bit values
// Access
reg [7:0] x;
x = cube[2][1]; // entry at row 2, col 1
x = tensor[1][2][3]; // entry at [1][2][3]Multi-dimensional arrays produce the same hardware as a flat memory with computed index: cube[i][j] is functionally equivalent to mem[i*4 + j]. The multi-dim syntax is just notational sugar.
The same restrictions from §6.2 apply — no slicing across the higher dimensions, no array-as-port, no array-as-literal.
For purely-Verilog-2001 codebases, multi-dim arrays are uncommon — most engineers flatten to a 1D memory with explicit index computation. SystemVerilog (the language extension) has stronger support for multi-dim arrays and removes most of the Verilog-2001 restrictions.
10. Simulation Behavior
The simulator stores vectors and arrays as packed bit arrays in memory:
- Scalar reg — 1 byte of simulator memory (overhead, since the actual bit value fits in much less).
- Vector reg [N-1:0] —
ceil(N / 32) * 4bytes (rounded to 32-bit words). - Array reg [N-1:0] mem [0:M-1] —
M * ceil(N / 32) * 4bytes.
For a 32 × 32-bit register file: 32 × 32 / 8 = 128 bytes of simulator memory. For a 1 KB byte memory: 1024 bytes (8 KB of memory if N=8 and the simulator stores X / Z bits separately).
Bit-selects and part-selects are computed at simulator runtime — the simulator extracts the relevant bits from the packed representation when the expression is evaluated. Dynamic bit-selects (data[idx]) produce a mux at synthesis time; the simulator emulates the mux with conditional branches.
11. Synthesis Behavior
The synthesis tool maps the three dimensions differently:
- Scalar reg → 1 flop (clocked) or 1 piece of combinational logic (
always @(*)with full coverage). - Vector reg [N-1:0] → N flops in parallel (clocked) or N parallel pieces of combinational logic.
- Array reg [N-1:0] mem [0:M-1] → for small M, N×M discrete flops + a multi-way mux for the read port. For large M, an inferred SRAM macro.
The threshold between "discrete flops" and "inferred SRAM" depends on the tool, the technology library, and the access pattern. Synopsys Design Compiler typically infers SRAM for memories above 256 entries with a synchronous read pattern; smaller memories or asynchronous-read patterns map to discrete flops. Xilinx Vivado infers BlockRAM for memories above 2 KB on most FPGAs.
`default_nettype none
// Pattern 1: synchronous write, asynchronous read → register file (small) or SRAM (large)
reg [7:0] mem [0:1023];
always @(posedge clk) if (wr_en) mem[wr_addr] <= wr_data;
assign rd_data = mem[rd_addr]; // async read
// Pattern 2: synchronous read → almost always SRAM
reg [7:0] mem [0:1023];
reg [7:0] rd_data_q;
always @(posedge clk) begin
if (wr_en) mem[wr_addr] <= wr_data;
rd_data_q <= mem[rd_addr]; // sync read
endPattern 2 (synchronous read) is the canonical SRAM-friendly pattern. Most FPGA BRAMs and ASIC SRAM macros have one cycle of read latency; the reg [7:0] rd_data_q; matches that latency naturally.
For a working RTL engineer, the rule is: declare memory with the access pattern that matches the desired implementation. Async-read patterns produce register files (small, fast); sync-read patterns produce SRAM (large, one-cycle latency). The synthesis tool's inference is deterministic for these canonical patterns.
12. Waveform Analysis
A waveform showing dynamic bit-select and part-select behaviour on a 16-bit vector.
Dynamic bit-select and part-select on a 16-bit vector
12 cyclesThe waveform illustrates the difference between bit-select (single bit, dynamic index legal) and indexed part-select (multi-bit slice, dynamic base via +:). Both are legal expressions; the bit-select produces a 1-bit result; the part-select produces a fixed-width slice.
13. Industry Use Cases
Three patterns that account for the vast majority of dimension choices in production RTL.
13.1 Scalar for control signals
Every RTL block has dozens of single-bit control signals: enables, valids, readys, flags, status bits, error indicators. These are all scalar. Naming convention: descriptive names (wr_en, valid_q, error_flag) rather than abbreviations.
13.2 Vector for data paths
Every RTL block has multi-bit data paths: counters, addresses, data values, packet headers, register contents. These are all vectors with explicit width. Naming convention: descriptive names with width suffix when ambiguity exists (addr_q, data_in, count_q). The explicit width is part of the design contract.
13.3 Array for memories
Register files (small), SRAMs (large), lookup tables (any size), packet buffers, FIFO storage, decoder tables. All arrays. Naming convention: descriptive names with optional _mem or _arr suffix (reg_file, cache_mem, coeff_tbl).
The dimension choice is the design decision. The synthesis tool produces the gates that match.
14. Common Mistakes
Five pitfalls that catch engineers using dimensions.
14.1 Reversed vector range
Writing reg [0:7] data; (ascending) when convention is reg [7:0] data; (descending). The reversed range works inside the module but causes byte-order bugs when the module's vector is concatenated with vectors from other modules using the convention. Always use [N-1:0] for vectors.
14.2 Reversed array range
Writing reg [7:0] mem [255:0]; (descending) when convention is reg [7:0] mem [0:255]; (ascending). The reversed range works but produces "address goes backwards" confusion. Always use [0:M-1] for arrays.
14.3 Slicing across array entries
mem[3:5] is illegal. Cannot get a sub-range of entries as a single value. Use a loop or multiple statements.
14.4 Forgetting the array initialisation
Arrays start at X on every bit at t = 0. Reading from an array before writing produces X-propagation. Reset every entry in synthesisable RTL (via a generate loop), or use $readmemh() for initial values from a file.
14.5 Width mismatch on bit-select assignment
reg [7:0] data;
reg bit_val;
bit_val = data[idx]; // bit_val is 1-bit, data[idx] is 1-bit — match
// BUT: bit_val = data; → 7-bit truncation warning
reg [3:0] nibble;
nibble = data[7:0]; // 8-bit slice assigned to 4-bit reg — truncation warningWidth-mismatch warnings are common. The fix is explicit slicing or explicit width conversion.
15. Debugging Lab
Three dimension-related debug post-mortems
16. Coding Guidelines
- Use
[N-1:0]for vectors. Descending range. Convention across every working RTL house. Bit N-1 is the MSB. - Use
[0:M-1]for arrays. Ascending range. Entry 0 is the first; entry M-1 is the last. regfor procedural-assignment vectors;wirefor continuous-assignment vectors. The 5.2 type-family rule.- Use
+:for byte/word access with LSB-anchored base.word[byte_idx*8 +: 8]. Use-:only when the base is the MSB of the slice. - Always reset every entry of small arrays (register files). Generate loop in the reset path.
- Use
$readmemh()for large memory initialisation. Cleaner than 1000 lines of explicit assignments; works in some synthesis tools for FPGA flows. - No slicing across array entries. Use loops. Verilog-2001 limitation; SystemVerilog removes it.
- Use concatenation
{ , }for byte-packing. Replication{N{ }}for sign-extension and zero-padding.
17. Interview Q&A
18. Exercises
Three exercises that turn dimension choices into reflex.
Exercise 1 — Pick the dimension
For each signal description, recommend scalar, vector, or array.
| # | Signal description |
|---|---|
| 1 | A "valid" flag indicating output data is ready |
| 2 | A 12-bit address bus |
| 3 | A 16-entry × 32-bit register file |
| 4 | An "enable" signal for a counter |
| 5 | A 64-bit packet header |
| 6 | A 256-entry × 8-bit lookup table |
Hints. Single-bit flags / enables → scalar. Multi-bit single values → vector. Multiple entries → array.
Exercise 2 — Dynamic byte extraction
Write a Verilog module extract_byte that takes a 32-bit word and a 2-bit byte index, and returns the selected 8-bit byte. Specifications:
- Inputs:
wire [31:0] word,wire [1:0] byte_idx. - Output:
wire [7:0] byte_out. - Behaviour:
byte_idx=0→ byte_out = word[7:0];byte_idx=1→ word[15:8]; etc.
Hints. Use the +: indexed part-select: word[byte_idx*8 +: 8]. The expression is one line.
Exercise 3 — Spot the dimension bugs
The following module has three dimension-related bugs. Identify and fix each.
module buggy (
input wire clk,
input wire rst_n,
input wire [0:31] data_in, // bug #1
input wire [1:0] byte_idx,
output reg [7:0] byte_out,
output reg err
);
reg [7:0] history [7:0]; // bug #2
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
byte_out <= 8'h00;
err <= 1'b0;
// bug #3: history not reset
end
else begin
byte_out <= data_in[7:0]; // also broken due to bug #1
err <= |history[3:0]; // bug #4
end
end
endmoduleWhat to produce. (a) Identify each bug. (b) Show the fix for each. (c) Explain why the broken version compiled but produced wrong results.
19. Summary
Verilog supports three dimensions for any variable or net:
- Scalar — 1 bit. Single-bit flags, enables, valids.
reg q;. - Vector — N bits, packed. Multi-bit values.
reg [N-1:0] q;. - Array — M entries × N bits. Register files, SRAMs, lookup tables.
reg [N-1:0] mem [0:M-1];.
The access operators on vectors:
- Bit-select —
data[i]returns the i-th bit (1 bit wide). - Fixed part-select —
data[7:0]returns a literal-bounded slice. - Indexed part-select (+:) —
data[base +: width]returns a width-bit slice starting at the variable base (LSB-anchored). - Indexed part-select (-:) —
data[base -: width]returns a width-bit slice ending at the variable base (MSB-anchored).
The access operators on arrays:
- Array index —
mem[i]returns the i-th entry (N bits wide). - Bit-select within an entry —
mem[i][j]returns bit j of entry i. - Part-select within an entry —
mem[i][7:0]returns the lower 8 bits of entry i.
The conventions:
- Vector range:
[N-1:0](descending). Bit N-1 is MSB. - Array range:
[0:M-1](ascending). Entry 0 is first.
The hardware mapping:
- Scalar → 1 flop.
- Vector → N flops in parallel.
- Array → N×M flops (small) or inferred SRAM (large).
The day-to-day discipline:
- Pick the dimension that matches the signal's role. Flags / enables → scalar. Multi-bit values → vector. Multiple entries → array.
- Always use
[N-1:0]for vectors,[0:M-1]for arrays. No exceptions. - Use
+:for byte / word access with LSB-anchored base.word[byte_idx*8 +: 8]. - No slicing across array entries. Use loops or multiple statements.
- Reset every array entry in synthesisable code. Generate loop in the reset path.
Section 5.2 closes here. The four sub-pages — reg-type, integer-type, real-type, and this one — cover every variable in Verilog. Chapter 5 closes; Chapter 6 picks up with constant variables (parameter, localparam) — the keywords that turn hard-coded values into design-time parameters.
Related Tutorials
- real — Chapter 5.2.3; the floating-point variable that shares the variable family.
- integer — Chapter 5.2.2; the 32-bit signed sibling.
- reg — Chapter 5.2.1; the workhorse variable type that all dimensions extend.
- Register Data Types — Chapter 5.2; the parent overview.
- Variables & Data Types — Chapter 5; nets and variables together.