VHDL Syntax Reference

(Author's Note: This document contains a reference on VHDL syntax that you may encounter during this course. It is by no means complete. There are many references available online that you may check for more complete material. The following is intended simply to provide a quick and concise reference on commonly used syntax in VHDL.)


Table of Contents



  1. Logical Syntax
    1. Logical Expressions
    2. If-Then-Else Statements
    3. Case Statements

  2. Structural Syntax
    1. Signal Assignments
    2. Variable Assignments
    3. Processes
    4. Component Instantiations

  3. Data Types
    1. Logical Types
    2. Ranged Types

  4. Module Structure
    1. Library
    2. Entity
    3. Architecture

  5. Declarations
    1. Signal Declarations
    2. Constant Declarations
    3. Function Declarations
    4. Component Declarations
    5. Variable Declarations
    6. Type Declarations

I. Logical Syntax


A. Logical Expressions

The basis of most of the VHDL that you will write is the logical interactions between signals in your modules. Most of this is very intuitive, representative of logical functions that you should already know.

B. If-Then-Else Statements

Another commonly used form of syntax will be the conditional statements. These work very much like the conditional statements of procedural programming that you should be used to. Pay close attention, however, to the slightly different syntax.

C. Case Statements

Case statements are quite useful in state machines and in code translations (eg. keyboard scan code interpretations).

II. Structural Syntax


A. Signal Assignments

The most basic of complete VHDL statements, a signal assignment is likely also one of the most common.

B. Variable Assignments

Variable assignments are not much different than signal assignments. The key difference is that the assignment operator is different. You can, however, assign from variables to signals and vice versa.

C. Processes

Processes are generally the backbone of your behavioural code. They facilitate clock-edge specification as well as synchronization among signal assignments. In general, you should be using processes when a signal assignment is dependent on changes in another. The dependency therein should be reflected in the process sensitivity list.

D. Component Instantiations

Just as processes are the backbone of your behavioural code, component instantiations are the key feature of your structural code.

III. Data Types


A. Logical Types


B. Ranged Types

There are a couple of ways to represent numbers in VHDL. One is to use the binary/hexadecimal representation afforded by the std_logic_vector. While this is useful when representing physical signals, integers are easier to use. As such an integer type and two subtypes have been defined in VHDL. There is, however, a catch. Integers are not implemented in wires. They are translated to busses. Thus, to limit the physical wires that are implemented by the design, and hence make the implementation of the design more efficient, we prefer to limit integers to specified ranges.

IV. Module Structure



A. Library

Libraries contain functions and types that you will need to complete the module defined below. These tools are contained in packages that are accessed by the keyword use.

B. Entity

An entity should define the interface for your module. Beyond the entity is <entity_name>, and of course the end entity statements, there are two items that go here that are of use in this course:
These are put together to form an entity declaration.
    Syntax:

    entity <entity_name> is
    port(

    port assignments
    ...
    -- all port assignments are followed by semi-colons
    -- except the last one

    );
    generic(

    generic assignments
    ...
    -- all generic assignments are followed by semi-colons
    -- except the last one

    );
    end [entity | <entity_name>];

    Example:

    entity or_entity is
    port(
    input_1: in std_logic;
    input_2: in std_logic;
    output: out std_logic
    );
    end or_entity;

C. Architecture

An architecture encompasses many other features of VHDL syntax. We will deal with those which are most useful to this course to follow. For now, we will simply list them.
    Syntax:

    architecure <architecture_name> of <entity_name> is
    [
    component declarations (detail)
    function declarations
    (detail)
    signal declarations
    (detail)
    constant declarations
    (detail)
    variable declarations
    (detail)
    type declarations
    (detail)
    ...
    -- there are others, but these are what you'll need
    -- for this course


    ]
    begin
    [
    combinatorial statements
    sequential statements
    ...

    ]
    end architecture;

    Example:

    architecture or_entity_arch of or_entity is

    begin
    output <= input_1 or input_2; end architecture;




V. Declarations



A. Signal Declarations

Very often, you will need internal signals within the behaviour portion of your architecture. This could be to store an internal value or to connect components, but the declarations remain the same and are all made between the is and the begin keywords of the architecture.
    Syntax:

    signal <signal_name> : type;

    -- you can add an initial value, but these are only supported
    -- in simulation and not for synthesis

    Examples:

    signal port_i : std_logic;
    signal bus_signal: std_logic_vector(15 downto 0);
    signal count: integer range 0 to 31;


B. Constant Declarations

Occasionally, you will need to declare constants. Some common uses include making understandable names for states in a state machine and setting maximum values for ranges of integers.
    Syntax:

    constant <constant-name> : type := <initial value>;

    -- naturally, you should always have an initial value

    Examples:

    -- state values
    constant state_1 : std_logic_vector := "01";
    constant state_2 : std_logic_vector := "10";

    constant addr_max: integer := 1024; -- maximum address value


C. Function Declarations

Though you will not have to use them frequently, functions can be useful for repeated use of code. For example, in the calculator lab, a function for evaluating an operation has been created to make it easier create the state machine therein.
    Syntax:

    function <function_name> (
    -- function arguments
    <signal_1> : type; . . . < signal_n> : type
    )
    returns return type is

    constant declarations
    variable declarations
    ...
    begin

    statements
    ...

    end <function_name>;

    Example:

    function sign_extend (
    narrow_bus: std_logic_vector(15 downto 0)
    )
    return std_logic_vector(31 downto 0) is

    variable output: std_logic_vector(31 downto 0);
    begin

    output(15 downto 0) <= narrow_bus(15 downto 0);
    -- lower 16 are the same
    output(31 downto 16) <= (others => narrow_bus(15));
    -- upper 16 are sign-extension of MSB
    return output;

    end sign_extend;


D. Component Declarations

You will be using these quite frequently as they are a key to the structural descriptions of your designs. Essentially, these are an interface declaration so the architecture knows what it's working with. Syntax checkers will work okay if this declaration matches its use, but this will only synthesize if the declaration matches an existing component. Very often, hence, you can simply copy the entity declaration of the component and change the keywords entity to component.
    Syntax:

    component <component_name> is
    port (

    port declarations as done
    in
    entity declarations
    ...

    );
    generic(

    generic declarations as done
    in
    entity declarations
    ...

    );
    end component;

    Example:

    component or_entity is
    port(
    input_1: in std_logic;
    input_2: in std_logic;
    output: out std_logic
    );
    end component;


E. Variable Declarations

Variables are useful in keeping track of certain values within the context of a process or a function, but cannot be used outsides processes or functions. Furthermore, they do not necessarily represent a wire in the device and are treated by the synthesizer tools sequentially. This means that they do not necessarily behave as signals do.
    Syntax:

    variable <variable_name> is : type;

    Examples:

    variable count_v: integer range 0 to 15;
    variable data_v: std_logic_vector(7 downto 0);
    variable condition_v: boolean;


F. Type Declarations

  • Type

  • The type keyword allows you to define your own data type in VHDL. These are interpreted and subsequently synthesized by synthesis tools. You can use types to create your own data types or arrays of existing data types.

    Syntax:

    type <type_name> is (<values>);

    -- where values is a list of acceptable values
    -- array types can be defined as follows:

    type <type_name> is array (<low> to <high>) of <data_type>;
    type <type_name> is array (<high> downto <low>) of <data_type>;

    Examples:

    type enum_type is (a, b, c, ..., z);
    type int_array is array(3 downto 0) of integer;
    type sl_vector_array is array(0 to 15) of std_logic_vector;

  • Subtypes

  • The subtype keyword is another way of defining types. Subtypes are used to restrict the values that a certain type can take.

    Syntax:

    subtype <subtype_name> is <type_name> range <low> to <high>;
    subtype <subtype_name> is <type_name> range <high> downto <low>;

    Examples:

    subtype addr_int is integer range 0 to 65535;
    subtype sub_enum_type is enum_type range a to m;






[Return to CMPUT 329 Lab Home Page]
Created by Paras Mehta, 2003