Attribute LENGTH

I don’t like magic numbers or redundant variables in the code. They make it unclear and unreadable. Fortunately, VHDL gives many various options to eliminate such parts. One of them are predefined attributes. VHDL delivers many groups of attributes, which are useful in many situations. Some of them work only with signals, other with specific data types etc., but in general, rule of using an attribute is always the same:

object‘attribute

First, very popular, attribute which I am going to focus on, is attribute length. I use it mostly in three situations:

  • when a type is defined in another package
  • when there is an unconstrained array
  • when there is an unconstrained function or procedure.

Length attribute is generally used when the length of the object is not directly given or is unconstrained. Creating unconstrained arrays or functions allows keeping the code flexible, cause it can be adjusted to any length of the object, not just to one. Using length for unconstrained objects is not limited to arrays or functions, but can work also with i.e. ports.

Below I gave some examples to show how to use length attribute.

Type is defined in another package

Package

PACKAGE pkg IS
   CONSTANT c_TestVec :STD_LOGIC_VECTOR(12-1 DOWNTO 0) := x"100";
   TYPE TypeA IS ARRAY (1 TO 3) OF UNSIGNED(16-1 DOWNTO 0);
END PACKAGE pkg;

Entity

ENTITY AttLenExtDef IS
   PORT (
      clk : IN STD_LOGIC;
      rst : IN STD_LOGIC;

      Aarr : IN  TypeA; 
      Barr : IN  TypeA;
      Yarr : OUT TypeA;

      Avec : IN STD_LOGIC_VECTOR(c_TestVec'LENGTH-1 DOWNTO 0);
      Yvec : OUT STD_LOGIC_VECTOR(c_TestVec'LENGTH-1 DOWNTO 0)
      );
END AttLenExtDef;

Type TypeA does not need any parameter. It is already defined in the package.

To define lengths of Avec and Yvec vectors, attribute length was used. Now their lengths are corelated with constant c_TestVec. Change of the constant will change the port.

Architecture

calc : PROCESS(clk)
   BEGIN
      IF rising_edge(clk) THEN
         IF rst = '1' THEN
            Yarr <= (OTHERS => (OTHERS => '0'));
            Yvec <= (OTHERS => '0');
         ELSE
            FOR i IN 1 TO TypeA'LENGTH LOOP
               Yarr(i) <= Aarr(i) + Barr(i);
            END LOOP;

            Yvec <= Avec;
         END IF;
      END IF;
   END PROCESS;

Attribute length is used in for loop. One loop assigns values to every vector in the array Yarr. Size of the array is not an issue, it will work for every size.

Unconstrained array

Package

PACKAGE pkg IS
   TYPE TypeB IS ARRAY (NATURAL RANGE <>) OF UNSIGNED(16-1 DOWNTO 0);
END PACKAGE pkg;

Entity

ENTITY AttLenArr IS
   PORT (
      clk : IN STD_LOGIC;
      rst : IN STD_LOGIC;

      Aarr : IN  TypeB;
      Barr : IN  TypeB;
      Yarr : OUT TypeB
      );
END AttLenArr;

TypeB is not fully constrained. Entity AttLenArr does not know the length of the array.  It will be constrained one level above, where AttlenArr is instantiated (in my case that is testbench).

Architecture

calc : PROCESS(clk)
   BEGIN
      IF rising_edge(clk) THEN
         IF rst = '1' THEN
            FOR i IN 1 TO Yarr'LENGTH LOOP
               Yarr(i) <= (OTHERS => '0');
            END LOOP;            
         ELSE
            FOR i IN 1 TO Yarr'LENGTH LOOP
               Yarr(i) <= Aarr(i) + Barr(i);
            END LOOP;
         END IF;
      END IF;
   END PROCESS;

Length can be every size and for every value, that process will do the same job. It is independent on the length of the array.

Testbench with AttLenArr instantiation

  SIGNAL Aarr : TypeB(4 DOWNTO 1);
   SIGNAL Barr : TypeB(4 DOWNTO 1);
   SIGNAL Yarr : TypeB(4 DOWNTO 1);

   ...
   ...
   ...

   UUT : AttLenArr
      PORT MAP (
         clk  => clk,
         rst  => rst,
         Aarr => Aarr,
         Barr => Barr,
         Yarr => Yarr
         );

Testbench defines length of the signals and use them as inputs to entity AttLenArr. Change the length in declaration, will cause the change of the signals’ length in AttLenArr entity.

Unconstrained function or procedure

Entity

ENTITY AttLenFun IS
   PORT (
      A : IN  UNSIGNED(8-1 DOWNTO 0);
      B : IN  UNSIGNED(8-1 DOWNTO 0);
      C : IN  UNSIGNED(8-1 DOWNTO 0);
      Y : OUT UNSIGNED(8-1 DOWNTO 0)
      );
END AttLenFun;

Here package is not used. Entity defines length of all signals.

Architecture

ARCHITECTURE rtl OF AttLenFun IS

-- a, b, c - the same length
FUNCTION Add3 (a, b, c : UNSIGNED) RETURN UNSIGNED IS
	VARIABLE y :UNSIGNED(a'LENGTH-1 DOWNTO 0);
BEGIN
   y := a + b + c;
   RETURN y;
END Add3;

BEGIN
   Y <= Add3(A, B, C);
END ARCHITECTURE;

In architecture, there is a function, which adds 3 values. Function does not use any constant lengths. It will be synthesised for lengths of the arguments. That kind of function can be used in many places. It should be noted that, just for example purposes, all arguments to the function have the same length.

*** *** ***

All source codes used in that post you can find on gitlab.com.

*** *** ***

Leave a Reply

Your email address will not be published. Required fields are marked *