Learning BSV‎ > ‎Data Types‎ > ‎

Vector

Overview

A vector is an abstract data type which is a container of a specific length, holding elements of one type.

  • To use vectors you must import the Vector package
import Vector :: * ;
  • The package includes many functions which create and operate on vectors
  • Complete documentation on vectors is found in the appendix of the Reference Manual

Syntax

typedef struct Vector#(type numeric vsize, type element_type); 
  • vsize represents the length of the vector, i.e. how many elements are in the vector
  • element_type represents the type of the contents of the vector
  • If the elements are in the Bits class, then the vector is as well. Thus a vector of these elements can be stored into Registers or FIFOs; for example a Register holding a vector of type int.
  • A vector can also store abstract types, such as a vector of Rules or a vector of Reg interfaces. These are useful during static elaboration although they have no hardware implementation.
  • Vectors can be compared for equality if the elements can. That is, the operators == and != are defined.

Examples

Create a new vector, my_vector, of 5 elements of datatytpe Int#(32), with elements which are undefined.

Vector #(5, Int#(32)) my_vector;

Vectors are zero-indexed; the first element of a vector v, is v[0]. When vectors are packed, they are packed in order from the LSB to the MSB.

Vector#(5, Bit#(7)) v1;

From the type, you can see that this will back into a 35-bit vector (5 elements, each with 7 bits).

typedef struct { Bool a, UInt#(5) b} Newstruct deriving (Bits);
Vector#(3, NewStruct) v2;

The structure, Newstruct packs into 6 bits. Therefore, v2 will pack into an 18-bit vector.

Functions

The Vector package contains many functions for creating, modifying and working with vectors. See the Reference Manual for a complete listing of functions. Here are described some of the more common functions.

  • newVector: Generate a vector with undefined elements.
  • genVector: Generate a vector containing integers 0 through N-1, where vector[0] will have the value 0.

Create a new vector, my_vector, of 5 elements of datatytpe Integer with elements 0, 1, 2, 3 and 4.

Vector #(5, Integer) my_vector = genVector;
  • replicate: Generate a vector by replicating a given argument.

Create a vector, my_vector, of five 1's.

Vector #(5,Int #(32)) my_vector = replicate (1);
  • genWith: Generate a vector by applying a given function.
  • [i] The square-bracket notation is available to extract an element from a vector or update an element within it. Extracts or updates the ith element, where the first element is [0]. Index i must be of an indexable type, (Integer, Bit, Int or UInt.)

Usage Tips

Don't use cons to build or construct a vector.

Cons is an inefficient way to build and populate a vector. The function will take a lot of time in static elaboration. Use one of the functions listed above.

Write to all elements of a Vector within a single rule.

If you write to the elements in separate rules, unique logic will be created for the update of each element. This will increase the logic in the generated design.

Determine if your design requires a Register of a Vector or a Vector of Registers.

A Register of a Vector is a large structure, so it will have all the issues related to large structures. When one field is updated in a register the entire register is updated, even if most of the fields do not change.

  • Use a Register of a Vector when you will be updating the entire vector together, at once in a single rule (atomically).
  • Use a Vector of Registers when you will be updating a single element at a time.

Assignments to a register of a large vector must include hold values to unchanged fields. This may lead to increased mux size, since all elements of the vector must be updated, even if they haven't all changed. This increases the size of the mux into the register.

If you have a Vector of Registers, and you dynamically pick a single register to update, the scheduler will think you are touching all the registers in the Vector. This can lead to rule conflicts, where none really exist.

A Register of a Vector:

import Vector :: *;
...
typedef enum { OK,
FAIL,
TEST,
WAIT
} Status deriving (Bits, Eq);
...
module ...
Reg#( Vector#(n,Status) ) status <- mkReg( replicate(OK) ) ;
...
rule updateStatus (failCond matches tagged Valid .chan );
status <= update( status, chan, FAIL ) ;
endrule
endmodule

A Vector of Registers:

import Vector :: *;
...
typedef enum { OK,
FAIL,
TEST,
WAIT
} Status deriving (Bits, Eq);
...
module ...
Vector#( n, Reg#(Status) ) status <- replicateM (mkReg (OK)) ;
...
rule updateStatus (failCond matches tagged Valid .chan);
status[chan] <= FAIL ;
endrule
endmodule
Comments