Featured post

Top 5 books to refer for a VHDL beginner

VHDL (VHSIC-HDL, Very High-Speed Integrated Circuit Hardware Description Language) is a hardware description language used in electronic des...

Sunday, 16 December 2012

Use Clause

Formal Definition

Achieves direct visibility of declarations that are visible by selection.

Simplified Syntax

use library_name.package_name.item;

use library_name.package_name;

use library_name.package_name.all;

Description

The use clause makes visible items specified as suffixes in selected names listed in the clause. In practice, the use clause makes visible declarations specified in packages and has the following form:

use library_name.package_name.item

If a designer wants to have all declarations in a package visible, then the 'item' clause should be substituted by the reserved word all.

The use clause is valid for the design unit immediately following it and for all secondary design units assigned to this design unit (if it is a primary design unit).

Examples

library IEEE;
use IEEE.Std_Logic_1164.all;
library IEEE;
use IEEE.Std_Logic_1164.Std_ulogic;
use IEEE.Std_Logic_1164.Rising_edge;

In the first example, all declarations specified in the package Std_Logic_1164 (which belongs to the library IEEE) have been made visible.

The second example makes visible the Rising_Edge function, which is declared in the same package. The function uses the type Std_ulogic, therefore declaration of this type is also made visible.

Important Notes

· Using multiple value logic and resolution functions requires using library clause and use clause like in the first example.

Variable Assignment

Formal Definition

A variable assignment statement replaces the current value of a variable with a new value specified by an expression.

Simplified Syntax

variable_name := expression ;

Description

The variable assignment statement modifies the value of the variable. The new value of the variable is obtained by assigning an expression to this variable. In order to distinguish variable assignment from signal assignment, the variable assignment symbol is different (:=).

The expression assigned to a variable must give results of the same type as the variable. The target at the left-hand side of the assignment can be either a name of a variable or anaggregate.

In the first case, the target can be in the form of simple name, selected name, indexed name or slice name (Example 1).

In case of aggregate as the target of the assignment, the type of the aggregate must be determinable from the context, including the fact that the type must be of the composite type. Each element of the aggregate must be in the form of the locally static name, which represents variable (Example 2).

The element association of aggregate, similarly to names, may have forms that are more complex: selected name, indexed name or slice name (Example 3).

Examples

Example 1

variable X, Y : REAL;
variable A, B : BIT_VECTOR (0 to 7);
type BIT_RECORD is record
  bitfield : BIT;
  intfield : Integer;
end record;
variable C, D : BIT_RECORD;
X := 1000.0;
A := B;
A := "11111111";
A (3 to 6) := ('1','1','1','1');
A (0 to 5) := B (2 to 7);
A (7) := '0';
B (0) := A (6);
C.bitfield := '1';
D.intfield := C.intfield;

The above examples of variable assignments are grouped in the following way: after the declarations the first group is a group of assignments with simple names as targets, then slice names, indexed names and finally selected names.

Example 2

variable E : BIT;
variable I : INTEGER;
(E, I) := C;

The aggregate used above as a target for a variable assignment could be used for the variable C declared in such a way as in the Example 1. E will be assigned the value of C.bitfield and I - C.intfield.

Example 3

type BIT_VECTOR_RECORD is record
  a: BIT_VECTOR(0 to 7);
  b: Integer;
end record;
variable G, H : BIT_VECTOR_RECORD;
(C.bitfield, C.intfield) := D; -- aggregate with selected name
(G.a(0 to 7), K) := H; -- aggregate with sliced name
(G.a(0), K) := D; -- aggregate with indexed name

Aggregates can use different forms of names.

Important Notes

· Variable assignment can be labeled.

· Variable assignment takes effect immediately.

· Variable assignment can not be specified with a delay.

Variable Declaration

Formal Definition

Variable is an object with a single current value.

Simplified Syntax

variable variable_name : type;

variable variable_name : type := initial_value;

Description

Variables are objects which store information local to processes and subprograms (procedures and functions) in which they are defined. Their values can be changed during simulation through the variable assignment statements.

A variable declaration includes one or more identifiers, a subtype indication and an optional globally static expression defining the initial value for the variable(s). The identifiers specify names for the variables, with one identifier per each variable. The variable can be declared to be of any type or subtype available, either constrained or unconstrained (Example 1).

The initial value of a variable can be assigned by a globally static expression. The expression must reference a value of the same type as the variable itself. If the variable is declared to be of a composite type other than a string, Bit_Vector or Std_Logic_Vector, then an aggregate must be used (see Example 2).

If the initial value of a variable is not specified, then it is implicitly set as the left bound of the type used. For example for a scalar named T, the default initial value will be T'LEFT. For a composite type, the initial value will be the aggregate consisting of the set of the default values of all the scalar elements. The default initial value for a variable of the access type isnull.

Variables declared in processes are initialized with their default values, given either explicitly or implicitly, at the start of the simulation. Variables declared in subprograms are initialized each time the subprogram is called.

The scope of variables is limited to the process or subprogram they are defined in. The only exception to this rule is a shared variable, which may be shared by multiple processes.

Variables can be also declared outside of a procedure or process to be shared between many processes. Shared variables may be declared within an architecture, block, generate statement or package. Declaration of a shared variable must be preceded by the shared keyword (Example 3).

Although the Language Reference Manual allows several processes to access a single shared variable it does not define what happens when two or more conflicting processes try to access the same variable at the same time. Such a situation may lead to unpredictable results and therefore should be avoided.

Examples

Example 1

type Mem is array (Natural range <>, Natural range <>) of Std_Logic;
variable Delay1, Delay2 : Time;
variable RAM1: Mem (0 to 1023, 0 to 8);

The type Mem is specified as an unconstrained memory (the limit depends on the implementation of the Natural subtype). The variable RAM1, specified in the third line, is based on the Mem type and is defined as a subtype constrained to a 1 KB memory.

Both Delay1 and Delay2 variables are of the Time type and are declared in the second line.

Example 2

type Mem is array (Natural range <>, Natural range <>) of Std_Logic;
variable TempCond : Boolean := true;
variable RAM2: Mem (0 to 7, 0 to 7):=
  (('0', '0', '0', '0', '0', '0', '0', '0'),
  ('0', '0', '0', '0', '0', '0', '0', '0'),
  ('0', '0', '0', '0', '0', '0', '0', '0'),
  ('0', '0', '0', '0', '0', '0', '0', '0'),
  ('0', '0', '0', '0', '0', '0', '0', '0'),
  ('0', '0', '0', '0', '0', '0', '0', '0'),
  ('0', '0', '0', '0', '0', '0', '0', '0'),
  ('0', '0', '0', '0', '0', '0', '0', '0'));

Both variables are initialized according to the types used. Note the aggregate has been used for initializing RAM2, which is an 88 bit memory.

Example 3

shared variable FreeAccess : Boolean := true;

The shared variable FreeAccess statement is used to determine whether a shared resource can be accessed at any particular time. However, in real applications a signal declaration would better serve for this purpose because using signals makes the specification more deterministic.

Important Notes

· Unlike signals, variables have neither history nor future, because according to its definition, each variable has only current value. No checking for the last event, time elapsed since the last event, previous value, etc. can be performed on variables.

· The non-shared variables are limited to subprograms and processes only.

· If a value of a variable is read before it is assigned in a clocked process (i.e. where operations are performed when an edge of clock signal is detected) then a register will be synthesized for this variable. A similar situation inside a combinatorial process may lead to generation of a latch.

· Variables declared in a subprogram are synthesized as combinatorial logic.

· During simulation variables consume a lot less (even an order of magnitude) memory space than signals. Therefore, it is highly recommended to use them for storage elements (such as memories) instead of signals.

· Shared variables may cause a system to be non-deterministic and therefore they should be avoided.

Vector

Description

Vector is another name for a one-dimensional array. It is used in particular for the arrays with elements of logical types: bit and std_logic (bit_vector and std_logic_vector, respectively).

Examples

signal DataBus : Bit_Vector(7 downto 0);
  . . .
DataBus <= "11000011";

Important Notes

  • Vectors of logical values are not directly transferable to integer values. Neither Standard package nor Std_Logic_1164 package define any conversion functions from logical vector to an integer or vice-versa. Most synthesis tools, however, support such functions (although these functions are tool-specific).
  • No arithmetic functions are allowed on logical vectors.

Vital

Formal Definition

VITAL (VHDL Initiative Towards ASIC Libraries) is an initiative, which objective is to accelerate the development of sign-off quality ASIC macro-cell simulation libraries written in VHDL by leveraging existing methodologies of model development.

Complete description: IEEE Standard 1076.4.

Description

VITAL, which is now standardized by IEEE, was created by an industry-based, informal consortium in order to accelerate the availability of ASIC (Application Specific Integrated Circuits) libraries for use in industrial VHDL simulators. As a result of the effort a new modeling specification has been created.

VITAL contains four main elements:

  • Model Development Specification document, which defines how ASIC libraries should be specified in VITAL-compliant VHDL in order to be simulated in VHDL simulators.
  • VHDL package Vital_Timing, defining standard types and procedures that support development of macro-cell timing models. The package contains routines for delay selections, timing violations checking and reporting and glitch detection.
  • VHDL package Vital_Primitives, defining commonly used combinatorial primitives provided both as functions and concurrent procedures and supporting either behavioral or structural modeling styles, e.g. VitalAND, VitalOR, VitalMux4, etc. The procedure versions of the primitives support separate pin-to-pin delay path and GlitchOnEvent glitch detection. Additionally, general purpose Truth Tables and State Tables are specified which are very useful in defining state machines and registers.
  • VITAL SDF map - specification that defines the mapping (translation) of Standard Delay Files (SDF), used for support timing parameters of real macro-cells, to VHDL generic values.

MODELING SPECIFICATION

The modeling specification of VITAL defines several rules for VHDL files to be VITAL-compliant. This covers in particular:

  • Naming conventions for timing parameters and internal signals, including prefixes for timing parameters, which must be used in the generics specifications (Example 1);
  • How to use the types defined in the Vital_Timing package for specifications of timing parameters;
  • Methodology of coding styles;
  • Two levels of compliance: level 0 for complex models described at higher level, and level 1, which additionally permits model acceleration.

A VITAL-compliant specification consists of an entity with generics defining the timing parameters of the ports (Example 1) and an architecture that can be written in one of two coding styles: either pin-to-pin delay style or distributed delay style.

PIN-TO-PIN DELAY MODELING STYLE

An architecture that follows this style contains two main parts (Example 2):

  • A block called Wire_Delay, which defines input path delays between input ports and internal signals. This block calls the concurrent procedure VitalPropagateWireDelay.
  • A process called VitalBehavior. This process may contain declarations of local aliases, constants and variables. It has a very rigid structure and is divided into three parts:
    • Timing Checks - does calls to procedure VitalTimingCheck which is defined in the package Vital_Timing.
    • Functionality - makes one or more calls to subprograms contained in the Vital_Primitives package and assignments to internal temporal variables. No wait statements, signal assignments or control structures are allowed here.
    • Path Delay - contains a call to VitalPropagateDelay for each output signal.

DISTRIBUTED DELAY MODELING STYLE

In this style the specification (ASIC cell) is composed of structural portions (VITAL primitives), each of which has its own delay. The output is an artifact of the structure, events and actual delays. All the functionality is contained in one block, called Vital_Netlist and this block may contain only calls to primitives defined in the Vital_Primitives package.

Examples

Example 1

library IEEE;
use IEEE.Std_Logic_1164.all;
library VITAL;
use VITAL.Vital_Timing.all;
use VITAL.Vital_Timing;
use VITAL.Vital_Primitives.all;
use VITAL.Vital_Primitives;
entity Counter is
  generic(tpd_ClkOut1 : DelayType01 := (10 ns, 10 ns);
  . . .);
  port (Reset : in Std_Logic := 'U';
    Clk : in Std_logic := 'U';
    CntOut : out Std_logic_Vector(3 downto 0));
end Counter;

This entity is a part of a VITAL-compliant specification of a four-bit synchronous counter with reset. Note that two libraries and three packages are used. In particular, multiple value logic types, defined in Std_Logic_1164, are standard logical types for VITAL.

The example given here specifies the propagation delay between the Clk input and the output number 1. The VITAL prefix tpd determines the timing parameter. The type used is specified in the Vital_Tming package.

Example 2

architecture PinToPin of Counter is
-- declarations of internal signals
begin
-- Input path delay
  Wire_Delay: block
  begin
  -- calls to the VitalPropagateWireDelay procedure
  Vital_Timing.VitalPropagateWireDelay (. . .);
  . . .
end block;
-- Behavior section
VitalBehavior: process(. . .)
  -- declarations
begin
  -- Timing Check
  Vital_Timing.VitalTimingCheck (. . .);
  -- Functionality
  Vital_Primitives.VitalStateTable (. . .);
  -- Path Delay
  Vital_Timing.VitalPropagatePathDelay (. . .);
  Vital_Timing.VitalPropagatePathDelay (. . .);
end process VitalBehavior;
end PinToPin;

The above listed architecture PinToPin is a template of a pin-to-pin modeling style. All its procedure calls should be specified with appropriate parameters.

Example 3

architecture DistrDelay of Counter is
  -- internal signals declarations
begin
-- Input path delay
Vital_Netlist: block
  -- internal declarations of the block
  begin
  -- calls to VITAL primitives, for example
  Vital_Primitives.VitalAND2(. . .);
  Vital_Primitives.VitalBuf(. . .);
  Vital_Primitives.VitalStateTable(. . .);
  end block;
end DistrDelay;

The above listed Architecture DistrDelay is a template of a distributed delay modeling style. All its procedure calls should be specified with appropriate parameters.

Saturday, 15 December 2012

Wait Statement

Definition:

The wait statement is a statement that causes suspension of a process or a procedure.

Simplified Syntax

wait;

wait on signal_list;

wait until condition;

wait for time;

Description

The wait statement suspends the execution of the process or procedure in which it is specified. Resuming the process or procedure depends on meting the condition(s) specified in the wait statement. There are three types of conditions supported with wait statements: sensitivity clause, condition clause, and timeout clause.

The most often used is the sensitivity clause. A sensitivity list defines a set of signals to which the process is sensitive and causes the process to resume (example 1).

If a wait statement does not contain a sensitivity list, then an implicit sensitivity list is assumed, one which contains all the signals that are present in that condition. If a process is resumed but no condition is met, then the process will not execute any other statements (example 2).

The second type of a condition supported with the wait statement is the condition clause. A process is resumed when the logical condition turns true due to a change of any signal listed in the condition (example 2).

The timeout clause defines the maximum time interval during which the process is not active. When the time elapses, the process is automatically resumed (example 3).

A single wait statement can have several different conditions. In such a case the process will be resumed when all the conditions are met (example 4).

If a wait on sensitivity_list is the only wait in the process and the last statement of the process, then it can be substituted by a sensitivity list of a process. See sensitivity list for details.

The syntax of the wait statement allows to use it without any conditions. Such a statement is equivalent to wait until true, which suspends a process forever and will never resume. While in simulation of normal models this is a disadvantage, this particular feature of a wait statement is widely used in testbenches. Example 5 shows an example of a testbench section.

Examples

Example 1

signal S1, S2 : Std_Logic;
. . .
process
  begin
   . . .
   wait on S1, S2;
end process;

After executing all statements, the process will be suspended on the wait statement and will be resumed when one of the S1 or S2 signals changes its value.

Example 2

wait until Enable = '1';
-- this is equivalent to
--   loop
--     wait on Enable;
--     exit when Enable = '1';
--   end loop;

In this example, the wait statement will resume the process when the Enable signal changes its value to '1'. This is equivalent to the loop described in the comment below the first line. Please note that the process is resumed on any change of the Enable signal. However, it will awake the rest of the process only when the new value is '1'.

Example 3

wait for 50 ns;

A process containing this statement will be suspended for 50 ns.

Example 4

BIN_COMP : process
begin
wait on A, B until CLK = '1';
  . . .
end process;

The process BIN_COMP is resumed after a change on either A or B signal, but only when the value of the signal CLK is equal to '1'.

Example 5

G: process
begin
  G0 <= '1' after 5 ns,
        '0' after 10 ns,
        '1' after 15 ns,
        '0' after 20 ns;
  G1 <= '1' after 5 ns,
        '0' after 15 ns;
  wait;
end process G;

In this process the values of signals G1 and G0 are set to '11', '10', '01', and '00' at the time intervals 5, 10, 15 and 20 ns, respectively. When the wait statement is encountered, the process is suspended forever.

Important Notes

· The wait statement can be located anywhere between begin and end process.

· A process with a sensitivity list may not contain any wait statements.

Waveform

Definition:

A series of transactions, each of which represents a future value of the driver of a signal. The transactions in a waveform are ordered with respect to time, so that one transaction appears before another if the first represents a value that will occur sooner than the value represented by the other.

Syntax:

waveform ::= waveform_element { , waveform_element }

| unaffected

waveform_element ::= value_expression [ after time_expression ]

| null [ after time_expression ]

Description

The waveform statement appears on the right-hand side of the signal assignment statement. It supports new values for the signal, possibly together with expected delays when the changes of the values will take effect. Alternatively, in concurrent signal assignments, the reserved word unaffected can be used instead of new values.

Each waveform element is composed of an expression whose value will be assigned to the signal driver and optional time expression is defined following the reserved word after. The type of the expression appearing in the waveform element must be the same as the type of the target signal (Example 1).

If there is no time expression specified in the waveform element of the signal assignment statement, then the time delay is implicitly delcared as after 0 ns (Example 2).

An expression in a waveform can be substituted by the value null. This value can be assigned only to signals declared as guarded, additionally with a resolution function (Example 3).

If the reserved word unaffected is used as a waveform in a concurrent signal assignment, it is equivalent to a process executing a null statement.

Evaluation of a waveform element produces a single transaction, i.e. a pair: new value for a signal and time when this value will be assigned. The time is determined by the current simulation time added to the value of time expression in the waveform element.

Examples

Example 1

signal D_OUT, E_OUT : BIT_VECTOR (3 downto 0);
.............................
D_OUT <= "0000" after 2 ns;
E_OUT <= "0000" after 2 ns, "1111" after 7 ns;

In the first signal assignment statement the "0000" value will be assigned to the driver D_OUT after 2ns. In the second assignment, first the "0000" value will be assigned to the E_OUT after 2ns and then after additional 5 ns the signal will be assigned the "1111" value.

Example 2

C_OUT <= 'X';
if C_OUT = 'X' then ...

Although the signal assignment will take place "after 0 ns", it is not immediate and when the if statement is executed, C_OUT will still have its value unchanged. Update of the C_OUT signal will take place at the end of simulation cycle, i.e. when the process is suspended.

Example 3

architecture test_null of test is
function res_fun (res_val: bit_vector) return bit is
begin
  for i in res_val'RANGE loop
    if res_val (i) = '1' then return '1';
    end if;
    return '0';
  end loop;
end res_fun;
signal H : res_fun BIT register;
begin
P1: process
begin
  A1: H <= '1' after 10 ns, null after 20 ns;
end process P1;
P2: process
begin
  A2: H <= '1' after 5 ns, '0' after 10 ns;
end process P2;
end architecture test_null;

When the signal assignment statements A1 and A2 are executed:

  • two transactions are placed in driver of the signal H in process P1 ('1' after 10 ns), (null after 20 ns) and
  • two transactions are placed in driver of the signal H in process P2 ('1' after 5 ns), ('0' after 10 ns)..

This means that the value of the signal H at 5 ns is determined by the resolution function with the value from process P2 equal to '1' and the value from process P1 equal to '0'. After 10 ns the resolution function will be called with '1' from process P1 and '0' from process P2. After 20 ns the resolution function will be called with a vector containing only one element ('0', contributed by process P2) as the driver from the process P1 is disconnected.

Important Notes

  • The delay values supported with the after clause do not cumulate, but all relate to the same simulation time (compare Example 1).