Verilog needs to represent individual bits as well as groups of bits. For example, a single bit sequential element is a flip-flop. However a 16-bit sequential element is a register that can hold 16 bits. For this purpose, Verilog has scalar and vector nets and variables.
Scalar and Vector
A net or
reg declaration without a range specification is considered 1-bit wide and is a scalar. If a range is specified, then the net or
reg becomes a multibit entity known as a vector.
wire o_nor; // single bit scalar net wire [7:0] o_flop; // 8-bit vector net reg parity; // single bit scalar variable reg [31:0] addr; // 32 bit vector variable to store address
The range gives the ability to address individual bits in a vector. The most significant bit of the vector should be specified as the left hand value in the range while the least significant bit of the vector should be specified on the right.
wire [msb:lsb] name; integer my_msb; wire [15:0] priority; // msb = 15, lsb = 0 wire [my_msb: 2] prior; // illegal
A 16 bit wide net called priority will be created in the example above. Note that the msb and lsb should be a constant expression and cannot be substituted by a variable. But they can be any integer value - positive, negative or zero; and the lsb value can be greater than, equal to or less than msb value.
Any bit in a vectored variable can be individually selected and assigned a new value as shown below. This is called as a bit-select. If the bit-select is out of bounds or the bit-select is x or z, then the value returned will be x.
reg [7:0] addr; // 8-bit reg variable [7, 6, 5, 4, 3, 2, 1, 0] addr  = 1; // assign 1 to bit 0 of addr addr  = 0; // assign 0 to bit 3 of addr addr  = 1; // illegal : bit8 does not exist in addr
A range of contiguous bits can be selected and is known as a part-select. There are two types of part-selects, one with a constant part-select and another with an indexed part-select.
reg [31:0] addr; addr [23:16] = 8'h23; // bits 23 to 16 will be replaced by the new value 'h23 -> constant part-select
Having a variable part-select allows it to be used effectively in loops to select parts of the vector. Although the starting bit can be varied, the width has to be constant.
[<start_bit> +: <width>] // part-select increments from start-bit [<start_bit> -: <width>] // part-select decrements from start-bit
module des; reg [31:0] data; int i; initial begin data = 32'hFACE_CAFE; for (i = 0; i < 4; i++) begin $display ("data[8*%0d +: 8] = 0x%0h", i, data[8*i +: 8]); end $display ("data[7:0] = 0x%0h", data[7:0]); $display ("data[15:8] = 0x%0h", data[15:8]); $display ("data[23:16] = 0x%0h", data[23:16]); $display ("data[31:24] = 0x%0h", data[31:24]); end endmodule
ncsim> run data[8*0 +: 8] = 0xfe // ~ data [8*0+8 : 8*0] data[8*1 +: 8] = 0xca // ~ data [8*1+8 : 8*1] data[8*2 +: 8] = 0xce // ~ data [8*2+8 : 8*2] data[8*3 +: 8] = 0xfa // ~ data [8*3+8 : 8*3] data[7:0] = 0xfe data[15:8] = 0xca data[23:16] = 0xce data[31:24] = 0xfa ncsim: *W,RNQUIE: Simulation is complete.
module tb; reg [15:0] data; initial begin $display ("data[0:9] = 0x%0h", data[0:9]); // Error : Reversed part-select index expression ordering end endmodule