Lesson 04: Verilog Scalar, Vector, and Array
A net or reg declaration without a range specification is considered 1-bit wide and is a scalar.
wire nor_o; // Single bit scalar net reg parity; // Single bot scalar variable
Vector (Packed Array, Bus)
If a range is specified, then the net or reg becomes a multibit entity known as a vector. A vector is also called a packed array, or a bus. Vectors are used to group related signals using one name to make them more convenient to manipulate. For example:
The syntax of vector:
- BIT_INDEXLEFT < BIT_INDEXRIGHT: [lsb_index:msb_index] Big-endian bit order.
- BIT_INDEXLEFT > BIT_INDEXRIGHT: [msb_index:lsb_index] Little-endian bit order.
Where msb_index is the most significant bit index and lsb_index is the least.
The sequence of a multiple-bits binary stored in memory is called bit-order. There are two types of bit-orders:
- Big-Endian Bit Order: The most significant bit is stored at the lowest bit address.
- Little-Endian Bit Order: The least significant bit is stored at the lowest bit address.
Most digital systems use the little-endian bit-order to store binary numbers, which means the bit 0 value is stored in the index=0 location.
Vectors are indexed from BIT_INDEXLEFT to BIT_INDEXRIGTH, that range gives the ability to address individual bits in a vector. Vectors can be declared for all types of net data types and reg data types. Specifying vectors for , , , and data types is illegal. Vector nets and registers are treated as unsigned values.
Notice that the declaration of a vector places the dimensions before the name of the vector, which is unusual compared to C syntax. However, the part selected has the dimensions after the vector name as you would expect.
reg [3:0] a; // Little-Endina Bit-Order reg [0:3] b; // Big-Endian Bit-Order wire c; a = 4'b1100; // a = 0, a = 0, a = 1, a = 1 b = 4'b1100; // b = 1, b = 1, b = 0, a = 0 c = (a == b); // c = 1
Switching Bits Ends
Verilog does not auto-convert the different bit-orders. The following code assigns big-endian to little-endian, but it would not work.
wire [0:7] be_byte; // 8-bit wire (big-endian) reg [7:0] le_byte; // 8-bit reg (little-endian) always @(posedge clk) le_byte <= be_byte; // Won't work :-(
Instead, you need to reverse the bits explicitly. All bits are swapped in parallel:
always @(posedge clk) begin le_byte <= be_byte; le_byte <= be_byte; le_byte <= be_byte; le_byte <= be_byte; le_byte <= be_byte; le_byte <= be_byte; le_byte <= be_byte; le_byte <= be_byte; end
Or in this case, a for-loop can be used to update each individual bit.
always @(posedge clk) begin for (i = 0; i < 8; i = i + 1) le_byte[i] <= be_byte[7-i]; end
Verilogis NOT like a software loop, it will be unrolled into parallel bit swaps as previous code.
Single Unit Select
The vector can be assigned as single units.
reg [7:0] address; // 8-bit vector reg variable [7, 6, 5, 4, 3, 2, 1, 0] address = 8'b1010_1111; // Assign 10101111 to address variable
Any bit in a vectored variable can be individually selected and assigned a new value, as known in the below example. This is called a bit select.
reg [7:0] address; // 8-bit vector reg variable [7, 6, 5, 4, 3, 2, 1, 0] address = 1; // Assign 1 to bit 0 of address address = 1; // Assign 1 to bit 4 of address address = 1; // illegal: index 8 does not exist in address variable
If the bit-select is out of the address bounds or the bit-select is x or z, then the value returned by reference shall be x.
The selection of the range of contiguous bits is called the part selected. There are two types of part-selects.
- Fixed Part-Select
- Indexed Part-Select
A fixed part-select of a vector reg or net is given with the following syntax:
reg [7:0] address; address[7:5] = 3'b101; // bits 7 to 5 will be replaced by the new value 'b101 --> fixed-select
An indexed part-select of a vector net, vector variable is given with the following syntax:
reg [7:0] data; data[5+:3] = 3'b010; // starting bit = 5, width = 3 ==> data[7:5]
reg [255:0] data1; // Little-endian bit order notation reg [0:255] data2; // Big-endian bit order notation reg [7:0] byte; // Using a variable part-select, one can choose parts byte = data1[31-:8]; // starting bit = 31, width =8 => data1[31:24] byte = data1[24+:8]; // starting bit = 24, width =8 => data1[31:24] byte = data2[31-:8]; // starting bit = 31, width =8 => data1[24:31] byte = data2[24+:8]; // starting bit = 24, width =8 => data1[24:31] // The starting bit can also be a variable. The width has to be constant. // Therefore, one can use the variable part-select in a loop to select all bytes of the vector for (i = 0; i <= 31; i = i + 1) byte = data1[(i*8)+:8]; // Sequence is [7:0], [15:8], ..., [255:248] // Can initialize a part of the vector data1[(byteNum*8)+:8] = 8'b0; // If byteNum = 1, clear 8 bits [15:8]
Multi-Dimension Vector (Multiple Packed Array Dimensions) is a SystemVerilog feature,
// Multiple Packed Array on support by SystemVerilog reg [0:2][0:2][0:2] rgb; rgb = 1'b0; // Assign one bit rgb = 3'h0A; // Assign one element rgb = 9'hbcd; // Assign slice rgb = 27'h01234; // Assign entire array as vector
An array declaration of a net or variable can be either scalar or vector. It is also called an unpacked array.
Array are allowed in Verilog for, , , real, and vector register data types.
A multi-dimensional array can be declared by having multiple dimensions after the array declaration. Each fixed-size dimension is represented by an address range, such as [0:1023].
SystemVerilog also supports a single value range, which is a single positive number to specify the size of a fixed-size array, such as . The notation size is equivalent to [0:size-1].
reg m1 [0:11]; // m1 is an scalar reg array of depth=12, each 1-bit wide reg [7:0] m2 [0:3]; // m2 is an 8-bit vector array reg with a depth=4 reg [7:0] m3 [0:1][0:3]; // m3 is an 8-bit vector 2D array rows=2, cols=4 each 8-bit wide reg [63:0] m4 [0:15][0:7][0:7][0:255]; // Four dimensional array integer count[0:7]; // An array of 8 count variables integer matrix[4:0][0:255]; // Two dimensional array of integer time chk_point[1:100]; // Array of 100 time checkpoint variables wire [7:0] w_array2 [0:5]; // Declare an array of 8=bit vector wire wire w_array1 [7:0][5:0]; // Declare an array of single bit wires // Single value range allowed only in SystemVerilog. reg [7:0] m4  // m4 is an 8-bit vectore array with 128 rows ==> same as reg [7:0] m4 [0:127]
In C language, arrays are indexed from 0 by integers or converted to pointers. The whole array can be initialized, and each element must be read or separately written in procedural statements.
In Verilog, arrays are indexed from INDEXFIRST to INDEXLAST. To access the array, the index number for every dimension has to be specified to access a particular element of an array. It can be an expression of other variables. The following statements are shown examples of accessing the array.
m1 = 1; // Illegal - m1 is an array. All elements in m1 can not be assigned in a single assignment m1 = 1'b0; // Assign 0 to m1 first element m2 = 8'hE2; // Assign 0xE2 to index=0 m2 = 8'h1A; // Assign 0x1A to index=2 m3 = 8'hBB; // Assign 0xBB to rows=1 cols=2 m3 = 8'hCC; // assign 0xCC to rows=0 cols=0