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.)

## 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.
 Syntax: [not] [[and | or | nor | nand | xor | xnor | ... ] []]; -- this type of expression can, naturally, be combined using logical functions Examples: not signal_1; signal_1 and signal_2; (not signal_1) and (signal_2 xor (signal_3 or (not signal_4)) xor signal_5);

### 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.
 Syntax: if then statements... [ elsif then statements... else statements... ] endif; Examples: if boolean_v then output_1 <= '1'; end if; --------------------------- if condition_v_1 = '1' then out_vector <= "001" elsif condition_v_2 = '1' then out_vector <= "110" ... else out_vector <= "000" end if;

### C. Case Statements

Case statements are quite useful in state machines and in code translations (eg. keyboard scan code interpretations).
 Syntax: case is when => ;... when ... [when others => ... ] end case; Example: case scancode is when x"14" => integer_signal <= 1; when x"18" => integer_signal <= 2; when x"19" | x"20" | x"21" => integer_signal <= 3; when others => integer_signal <= 0; end case;

## II. Structural Syntax

### A. Signal Assignments

The most basic of complete VHDL statements, a signal assignment is likely also one of the most common.
 Syntax: <= ; -- the expression must be of a form whose result matches the type of the assigned signal Examples: std_logic_signal_1 <= not std_logic_signal_2; std_logic_signal <= signal_a and signal_b; large_vector(15 downto 6) <= small_vector(10 downto 0);

### 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.
 Syntax: := -- the expression must be of a form whose result matches the type of the assigned variable Examples: boolean_v := true; temp_v(3 downto 0) := sl_vector_signal(7 downto 4);

### 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.
 Syntax: [:] process () variable declarations constant declarations ... begin statements... end process; Example: output_process: process(flag_signal) begin if flag_signal = '1' then output_vector <= "010"; else output_vector <= "101"; end if; end process;

### D. Component Instantiations

Just as processes are the backbone of your behavioural code, component instantiations are the key feature of your structural code.
 Syntax: : port map( => , ... ) -- you can also just list assigned signal names in the order you declared them in the component declaration, but this is not generally considered good coding style generic map( => , ... ); Examples: or_ent_1: or_entity port map( input_1 => input_1_sig, input_2 => input_2_sig, output => output_sig );

## III. Data Types

### A. Logical Types

• #### std_logic

• The std_logic data type is the most frequently used type in VHDL. It is part of the std_logic_1164 package in the IEEE library and is used to represents regular two-value logical values (as '0' and '1') as well as other common logic values like high impedence ('Z').
Further to this data type is the std_logic_vector, which represents busses in VHDL. This data type acts like an array of std_logic 'bits' in order represent such a collection.

 Examples: std_logic_signal <= '1'; std_logic_signal <= '0'; sl_vector_signal_8 <= "11110000"; -- an 8 bit vector sl_vector_signal_8 <= x"F0"; -- equivalent to above sl_vector_signal_8 <= sl_vector_signal_16(15 downto 8); -- you can assign from part of a larger vector std_logic_signal <= sl_vector_signal_8(5) -- access a single bit sl_vector_signal_8 <= (others => '0') -- set all bits to '0' MORE?!?!
• #### boolean

• Another logical type is the boolean type. It is a standard VHDL type and is used typically as a variable or as a constant to signify some sort of condition.

 Examples: constant CONDITION_C: boolean := false; variable bool_v: boolean := true;

### 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.
 Type: integer: -(231) to 231 - 1 -- note: this means it uses a 32 bit signed signal -- these are the subtypes of integer: positive: 1 to integer'high natural:  0 to integer'high Syntax: signal : integer range to ; --(or variable or constant) Examples: signal cycle_length: integer 0 to 15; -- this will be a 4 bit signal signal other_int: integer -1 to 15; -- this is 5 bits because it needs a sign variable ram_addr_v: natural 0 to ADDRMAX; -- you can also base your range on defined constants

## 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.

 Syntax: library ; use ..[all|]; Examples: library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all;

### 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:
• #### Port

The port statement involves declaration of the inputs and outputs of your design. This is the interface to your design, and the declarations here are read or set within the accompanying architecture.

 Syntax: : in|out|inout type; Examples: enable: in std_logic; data_bus: out std_logic_vector(7 downto 0);
• #### Generic

The generic statement declares signals that are analogous to arguments in functions in procedural programming. These signals are set in the file that is hierarchically above this one. If they are not set, they take the default value that you give it.

 Syntax: : type [:= ]; Examples: bus_width: integer := 8; my_boolean: boolean := false;

These are put together to form an entity declaration.
 Syntax: entity 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 | ]; 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 of 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 : 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 : type := ; -- 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 arguments : type; . . . < signal_n> : type ) returns return type is constant declarations variable declarations ... begin statements... end ; 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 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 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 is (); -- where values is a list of acceptable values -- array types can be defined as follows: type is array ( to ) of ; type is array ( downto ) of ; 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 is range to ; subtype is range downto ; Examples: subtype addr_int is integer range 0 to 65535; subtype sub_enum_type is enum_type range a to m;