Circuit Design 08

Understanding VHDL Packages and Components #

VHDL offers powerful tools for organizing and reusing code. Two of the most important features are packages and components. These features help make your code more modular and easier to maintain.

VHDL Packages #

A package is a collection of declarations that can be shared across multiple designs. Think of it as a toolbox that holds useful items you might need in different projects.

A package can have two parts:

  1. The package declaration (required)
  2. The package body (optional)

Package Declaration #

The package declaration contains only declarations, such as:

  • Type declarations
  • Signal declarations
  • Constant declarations
  • Component declarations
  • Subprogram declarations (functions and procedures)

Here’s a simple example:

PACKAGE my_package IS
  TYPE matrix IS ARRAY (1 TO 3, 1 TO 3) OF BIT;
  SIGNAL x: matrix;
  CONSTANT max1, max2: INTEGER := 255;
END PACKAGE;

Package Body #

The package body is only needed when you have subprograms (functions or procedures) or deferred constants in your package. It contains the full implementation of these items.

Here’s an example with both parts:

PACKAGE my_package IS
  CONSTANT flag: STD_LOGIC;  -- Deferred constant (no value yet)
  FUNCTION down_edge(SIGNAL s: STD_LOGIC) RETURN BOOLEAN;
END my_package;

PACKAGE BODY my_package IS
  CONSTANT flag: STD_LOGIC := '1';  -- Now we specify the value
  FUNCTION down_edge(SIGNAL s: STD_LOGIC) RETURN BOOLEAN IS
  BEGIN
    RETURN (s'EVENT AND s='0');
  END down_edge;
END my_package;

VHDL Components #

Components allow you to reuse existing circuits in new designs. This makes your code more modular and helps with creating hierarchical designs.

To use a component, you need to:

  1. Declare the component
  2. Instantiate the component

Component Declaration #

The component declaration must match the entity of the design you want to reuse:

COMPONENT nand3 IS
  PORT (a1, a2, a3: IN STD_LOGIC; b: OUT STD_LOGIC);
END COMPONENT;

Component Instantiation #

Component instantiation creates an actual instance of the component in your design:

nand_gate: nand3 PORT MAP (x1, x2, x3, y);

You can map ports in two ways:

  • Positional mapping: nand_gate: nand3 PORT MAP (x1, x2, x3, y);
  • Nominal mapping: nand_gate: nand3 PORT MAP (a1=>x1, a2=>x2, a3=>x3, b=>y);

GENERIC MAP #

GENERIC allows you to create flexible, reusable components. GENERIC MAP lets you change generic parameters when instantiating a component.

Here’s an example:

-- Component declaration
COMPONENT and_gate IS
  GENERIC (inputs: POSITIVE := 8);
  PORT (a: IN BIT_VECTOR(1 TO inputs);
        b: OUT BIT);
END COMPONENT;

-- Component instantiation with GENERIC MAP
a1: and_gate GENERIC MAP (16) PORT MAP (x, y);

In this example, we changed the number of inputs from the default 8 to 16.

Using GENERATE with Components #

GENERATE helps you create multiple instances of a component. This is useful for designs with repeated structures.

gen: FOR i IN 0 TO max GENERATE
  comp: my_component PORT MAP (x(i), y(i), z(i));
END GENERATE gen;

This code creates multiple instances of my_component, one for each value of i from 0 to max.

CONFIGURATION #

CONFIGURATION provides architecture-entity bindings. This is helpful in complex designs or when you have multiple architectures for one entity.

CONFIGURATION config1 OF test IS
  FOR arch1
  END FOR;
END CONFIGURATION;

This configuration binds the entity test to the architecture arch1.

BLOCK for Code Organization #

BLOCK helps partition your code into related sections. It’s like creating “zones” in your code to keep things organized.

controller: BLOCK
BEGIN
  -- Code related to the controller goes here
END BLOCK controller;

BLOCK can also have a guard expression that controls when the code inside executes:

blk: BLOCK (clk='1')
BEGIN
  q <= GUARDED d;  -- Only updates when clk='1'
END BLOCK blk;

VHDL 2008 Enhancements #

VHDL 2008 added several enhancements:

  1. More declaration types in packages
  2. GENERIC in package headers
  3. Package instantiation
  4. Expressions in PORT MAP assignments

For example, VHDL 2008 allows expressions in port mappings:

cir: my_circuit PORT MAP(inp => a AND b, outp => c);

Practical Approaches #

There are several ways to organize components in your designs:

  1. Method 1: Everything in one file
  2. Method 2: Components in separate projects with declarations in main code
  3. Method 3: Components in separate projects with declarations in a package

Method 3 is often the cleanest for complex designs.

Summary #

Packages and components are powerful tools for creating modular, reusable VHDL code. Packages let you share declarations across designs. Components let you reuse existing circuits. Together, they make your designs more organized and easier to maintain.

Using GENERIC MAP, GENERATE, CONFIGURATION, and BLOCK further enhances your ability to create flexible and well-structured code. These features are essential for creating complex digital systems in a manageable way.