TLDR
I sometimes come across VHDL code with suboptimal type names. I mean mainly the names of types aggregating objects of another type. There is nothing wrong with using arbitrary names. There is no VHDL police. You can name your types however you want. However, other engineers, or maybe even you from the future, will thank you if you stick to some very simple rules of thumb.
Most programming languages have more or less strict rules on what can be named as a vector, array, or list. I don't want to discuss the general overview of this topic in this post, as I want to focus solely on VHDL. VHDL is a hardware description language, and as such, it addresses problems in a different domain.
VHDL is a strongly-typed language. It doesn't allow implicit type conversions and enforces data type checks. Even if two types from the logical point of view look the same, they are not the same for a VHDL compiler. I mean distinct types here, not subtypes, which follow slightly different rules.
The main difference between vectors, arrays, and lists is that vectors and arrays have a runtime fixed size, while lists have runtime dynamic size. I don't mean that you have to constrain vector and array types during type definition. It is usually even better to have these types unconstrained, as such types are more flexible because the user can constrain them during object instantiation. What I mean, is that vector and array types sizes don't change during simulation or while your device is operating. Changing the vector or array size requires a change in the source code and recompilation.
The second difference is that vectors and arrays are frequently used for hardware description. They synthesize easily. On the other hand, lists, due to their dynamic nature, are used for simulations only. At least I have never seen VHDL lists being used for synthesizable logic. This is technically feasible if the compilers were able to deduce the maximum list size based on the description.
From the user's perspective, there is almost no difference between vectors and arrays. Almost, because they are indexed differently. This is a significant difference, as you will get an error during the analysis stage if you use improper indexing. That is why I like it when the type name clearly indicates to its users how its elements should be indexed.
I really like to follow the concept that vectors are syntactically one-dimensional and arrays can be syntactically n-dimensional. This is not a formal concept. I doubt you can find it in any international standard. I was first introduced to this concept by an older professor at my university (Warsaw University of Technology). Since then, I have never had to use LSP (Language Server Protocol) or grep through files to get to know how to properly index elements.
Now, let's move from the theory to practice. The snippet below is taken from my open-source APB library.
-- A one-dimensional array of data with the width equal to the APB maximum data width.type data_array_t is array (natural range <>) of std_logic_vector(31 downto 0);-- A two-dimensional array of data with the width equal to the APB maximum data width.type data_array_2d_t is array (natural range <>, natural range <>) ofstd_logic_vector(31 downto 0);-- An alias to the data_array_t.alias data_vector_t is data_array_t;-- A two-dimensional vector of APB data with maximum data width.type data_vector_2d_t is array (natural range <>) of data_vector_t;
There are a few things I would like to elaborate on.
data_vector_2d_t type.
data_vector_t is defined as an alias to the data_array_t type.
std_logic_vector.
Let's see what the difference between utilizing data_array_2d_t and data_vector_2d_t types is.
If you haven't understood me so far, now things should get clearer.
The snippet below presents how to define and use objects of both types.
-- Two-dimensional vector usage example.signal MEMORY_VECTOR : data_vector_2d_t(0 to 1)(0 to 1);MEMORY_VECTOR(0)(0) <= x"A5A5A5A5";-- Two-dimensional array usage example.signal MEMORY_ARRAY : data_array_2d_t(0 to 1, 0 to 1);MEMORY_ARRAY(0,0) <= x"A5A5A5A5";
From the semantical point of view, both MEMORY_VECTOR and MEMORY_ARRAY represent two-dimensional memory with equal overall capacity.
However, syntactically, they are indexed differently.
The vector version has two levels of one-dimensional indexing.
The array version has one level of two-dimensional indexing.
Moreover, from the VHDL perspective, these are two distinct types.
Lists have a dynamic size. They can shrink and grow during runtime. By runtime, I mean only simulation here. I have never seen lists getting synthesized into real hardware.
Lists are cumbersome in VHDL. There is no native support for lists in VHDL. Most of the time, they represent custom types and are implemented from scratch using protected types. Moreover, true lists can be implemented in VHDL as linked lists only. This is not an optimal implementation from the memory allocation perspective, as each element requires separate memory allocation. This can potentially significantly slow down the simulation and fragment your memory, which can slow it down even more. You probably won't notice this on any decent machine unless you allocate hundreds of thousands or millions of objects.
Compared to the vector and array examples, the list example requires more code. This is why I don't include it in this post. I think lists require their own post, so that they can be explained thoroughly.