In this blog, I will be exploring the first of two very handy VHDL "composite" types. These are called composite types because they are comprised of one or more -- and possibly different -- types or sub-types.
An array in VHDL is a collection of values, all of which are the same type or sub-type. Arrays are indexed by integers. Arrays may be 2D (two-dimensional), 3D (three-dimentional), or however many "D" you need. For myself, I haven't practically gone above three dimensions. You can have arrays of type unsigned, signed, std_logic_vectors, std_logic, boolean, or any other type you need.
Here is an example of an array type declaration and signal declaration using the array type with an initialization (the ieee.numeric_std library used throughout).
Accessing (reading/writing) arrays
One method of writing data into an array is as illustrated below:
One method of reading data from an array is as illustrated below:
Note that "f_adrs" could also have been declared as an "integer" to begin with, thereby eliminating the need to use the "to_integer" function to convert the "unsigned" type to an "integer" type. I just prefer to not use integers myself.
Using arrays: Modeling memory
I use arrays in multiple ways. The first, and probably most obvious, use is to model and/or infer memory. This memory could be external to my FPGA design -- perhaps a simulation model of a DDR chip or a DIMM. Alternatively, this could be used to infer Distributed RAM (DRAM) or Block RAM (BRAM) inside an FPGA, as opposed to instantiating vendor-generated cores/IP.
Below is an example from Xilinx -- the "rams_16b.vhd" example, which has been modified by myself to use the "numeric_std" library; also to have parameterized data width and array depth through the use of generics; also to use an attribute to force BRAM inference (click here to see a larger, more detailed version of this image):
Using arrays: Replication with loops
The second way I use arrays is for logic or instance replication alongside "generate" statements or "for" loops inside synchronous processes. An example of this is as follows:
Using arrays: Pipelining and shift registers
The third way I use arrays is for pipelining of non-single bit signals. This is handy for pure timing closure related pipelining or for constructing various digital signal processing components or architectures. An example of this is as follows (click here to see a larger, more detailed version of this image):
To Page 2 >